Compiler.ExpressionInString 1.0.2

dotnet add package Compiler.ExpressionInString --version 1.0.2
                    
NuGet\Install-Package Compiler.ExpressionInString -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Compiler.ExpressionInString" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Compiler.ExpressionInString" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Compiler.ExpressionInString" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Compiler.ExpressionInString --version 1.0.2
                    
#r "nuget: Compiler.ExpressionInString, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Compiler.ExpressionInString@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Compiler.ExpressionInString&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Compiler.ExpressionInString&version=1.0.2
                    
Install as a Cake Tool

Compiler.ExpressionInString

Compiler 编译时工具集之一。在类型为 string 的字段、属性或方法参数中编写 LINQ Lambda 表达式,并在编译期进行语义校验。

工具集规划:Compiler.ExpressionInString(本包)、Compiler.Sql(后续)等。

安装

dotnet add package Compiler.ExpressionInString

NuGet 包会自动引入 Roslyn Analyzer(Compiler.ExpressionInString.Analyzers)。若在解决方案内以项目引用方式使用,请确保 Analyzer 项目以 OutputItemType=Analyzer 被引用,否则 IDE/编译期校验不会生效。

功能

  • [ExpressionInString<TReturn>][ExpressionInString<T1, ..., T9, TReturn>] 共 10 种 Attribute(0~9 个 Lambda 参数 + 1 个返回值类型)
  • 最后一个泛型参数始终是 返回值类型
  • 可应用于 字段属性方法参数
  • Roslyn Analyzer 编译期校验(诊断码 EIS001
  • IDE 成员补全:在表达式字符串内输入 x. 时提供属性/方法补全(Visual Studio / Rider)
  • string.ToExpression<...>() 运行时解析为 Expression<Func<...>>

用法

using System.Linq.Expressions;
using Compiler.ExpressionInString;

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

// 方法参数:0 个 Lambda 参数,返回 int
void Query0([ExpressionInString<int>] string expr)
{
    Expression<Func<int>> lambda = expr.ToExpression<int>();
}

// 方法参数:1 个 Lambda 参数,返回 bool
void Query1([ExpressionInString<Student, bool>] string expr)
{
    Expression<Func<Student, bool>> lambda = expr.ToExpression<Student, bool>();
}

// 方法参数:第二个 Lambda 参数从相邻方法参数推断
void Query2<TArg>(
    [ExpressionInString<Student, FromParameter, bool>] string expr,
    TArg arg)
{
    Expression<Func<Student, TArg, bool>> lambda = expr.ToExpression<Student, TArg, bool>();
}

// 字段 / 属性:FromParameter 从定义该成员的类型的泛型参数按顺序推断
class Repository<TArg>
{
    [ExpressionInString<Student, FromParameter, bool>]
    public string Filter { get; set; } = "(x, arg) => x.Id > 0";
}

编译错误提示(EIS001)

Analyzer 会将字符串内的 Lambda 嵌入合成 C# 代码进行编译,并把 Roslyn 报错映射回字符串字面量内部,在 IDE 中以红色波浪线标出。

诊断信息

项目 说明
诊断码 EIS001
严重级别 Error(阻止生成)
标题 Invalid expression string
消息内容 转发 Roslyn 编译器原始错误信息(中文/英文取决于 IDE 语言设置)

触发校验的位置

仅对字符串字面量进行分析,包括:

  • 方法调用中传给带 Attribute 的参数
  • 带 Attribute 的字段 / 属性初始化器
  • 对带 Attribute 的字段 / 属性的赋值(右侧为字面量)

以下情况不会触发校验:

  • 变量、字段、属性间接传入(非字面量)
  • 字符串插值($"..."
  • 拼接表达式("a" + "b"
  • 空字符串或仅空白字符

错误定位规则

  • 能精确定位时,波浪线只覆盖表达式内的出错片段(例如错误的成员名 .Nick),而非整段字符串
  • 成员访问错误会尽量包含前导点号,显示为 .Nick 而非 Nick
  • 无法映射到字面量内部时,回退为标红整个字符串

常见错误示例

无效成员访问 — 属性/字段名不存在:

void Query([ExpressionInString<Student, bool>] string expr)
{
    Query("x => x.No > 0");
    //              ^^^ EIS001: 'Student' does not contain a definition for 'No'
}

返回值类型不匹配 — 与 Attribute 最后一个泛型参数不一致:

void Query([ExpressionInString<int>] string expr)
{
    Query("() => \"not int\"");
    //     ^^^^^^^^^^^^^^^ EIS001: cannot convert 'string' to 'int'
}

Lambda 参数数量或类型不匹配 — 与 Attribute 声明的参数类型不一致:

void Query([ExpressionInString<Student, bool>] string expr)
{
    Query("() => true");
    //     ^^^^^^^^^^ EIS001: delegate 'Func<Student, bool>' does not take 0 arguments
}

FromParameter 推断后的成员访问错误 — 方法参数或类型泛型参数解析后,同样做完整语义检查:

void Query<TArg>([ExpressionInString<Student, FromParameter, bool>] string expr, TArg arg)
{
    Query("(x, arg) => x.Id == arg.Id", new { Id = 1 }); // 合法
    Query("(x, arg) => x.Id == arg.Missing", new { Id = 1 });
    //                              ^^^^^^^ EIS001: 匿名类型/泛型参数上不存在该成员
}

与运行时解析的关系

  • 编译期(Analyzer):基于 Attribute 声明的类型做语义校验,不执行 Lambda
  • 运行时ToExpression):使用 System.Linq.Dynamic.Core 将字符串解析为 Expression<Func<...>>

两者使用不同的解析引擎,但语义规则一致。通过 EIS001 校验的表达式,在绝大多数情况下可正常调用 ToExpression;若运行时仍失败,请检查泛型类型参数是否在运行时可解析。

语法高亮

[StringSyntax("CSharp")] 无法用于 C# 表达式高亮。StringSyntaxAttribute 仅内置支持 Json、Regex、Xml 等语法,不包含 C#。

Roslyn 对 C# 嵌入字符串使用独立的 lang 注释,在字符串字面量前添加即可:

// 方法调用
Query1(
    /*lang=c#*/
    "x => x.Id > 0");

Query2(
    /*lang=c#*/
    "(x, arg) => x.Id == arg.Id",
    new { Id = 0 });

// 字段 / 属性初始化或赋值
[ExpressionInString<Student, bool>]
public string Filter { get; set; } =
    /*lang=c#*/
    "x => x.Id > 0";
IDE 支持情况
Visual Studio 2022 支持 /*lang=c#*/ / // lang=c#(需较新的 Roslyn 工具链)
JetBrains Rider 支持 /*lang=c#*/;也可在设置中配置 ExpressionInStringAttribute 的注入规则,或使用 LanguageInjectionAttribute
VS Code / Cursor C# 扩展对嵌入语言支持有限,高亮效果因扩展版本而异

说明:

  • lang 注释必须写在实际字符串字面量之前(调用点、初始化器、赋值处),写在参数/属性声明上无效
  • 语法高亮与 EIS001 校验相互独立:无 lang 注释仍可正常报错;有 lang 注释不会自动启用校验
  • 本包提供的 ExpressionInStringCompletionProvider 负责成员补全(x.),与语法高亮是互补能力

其他说明

  • Attribute 中不能使用 dynamic,请用 FromParameter 占位
  • 在方法参数上,FromParameter / FromParameterN调用点已绑定的方法形参类型推断(优先使用构造后方法的 Parameters[i].Type 及已推断的泛型实参替换,必要时回退到实参表达式类型)
  • FromParameter 按顺序消费第 1、2、3… 个调用点形参;FromParameterN 按索引选取第 N 个
  • 非顺序选取示例:[ExpressionInString<Student, FromParameter2, FromParameter1, bool>] 表示第 2 个 lambda 参数取自第 2 个形参、第 3 个取自第 1 个
  • 在字段或属性上,FromParameter 按顺序从类型泛型参数推断;FromParameterN 按索引选取第 N 个类型泛型参数(无调用点形参时的回退语义)
  • 字段/属性上通过 FromParameter 推断出的未约束泛型参数访问成员(如 arg.Id)会在校验期报错,需添加泛型约束;Analyzer 会将 where 约束传播到合成校验代码中

构建与测试

dotnet build Compiler.sln
dotnet test tests/Compiler.ExpressionInString.Tests
dotnet pack src/Compiler.ExpressionInString/Compiler.ExpressionInString.csproj -c Release
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 91 6/8/2026
1.0.1 92 6/5/2026
1.0.0 87 6/5/2026