如何为动态创建的Lambda表达式参数标记特性?
如何为表达式树生成的Lambda参数添加特性?
常规表达式树生成Lambda的方式(比如求和示例)无法直接为参数添加特性,因为Expression.Parameter()静态方法没有提供添加特性的入口。但我们可以通过Expression.MakeParameter()方法结合特性数据,实现给参数标记特性的需求,完全适配动态生成Minimal API端点这类场景。
目标效果
我们需要生成等价于以下代码的表达式树:
([FromServices] ISender sender, [FromBody] LoginDto body, CancellationToken ct) => sender.Send(new LoginQuery(body), ct)
实现步骤与代码示例
构造特性的CustomAttributeData
表达式树通过CustomAttributeData识别参数特性,我们可以直接从特性实例中获取该数据。用Expression.MakeParameter创建带特性的参数
替代Expression.Parameter(),使用Expression.MakeParameter()传入特性数据集合,生成带标记的参数。构建Lambda逻辑体并编译
按常规方式构建Lambda的执行逻辑,最后生成并编译完整的Lambda表达式。
完整代码示例:
using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc; // 假设ISender、LoginDto、LoginQuery已提前定义 // 生成[FromServices]特性的数据 var fromServicesAttrData = CustomAttributeData.GetCustomAttributeData(new FromServicesAttribute()); // 创建带[FromServices]标记的sender参数 var senderParam = Expression.MakeParameter( typeof(ISender), "sender", false, new[] { fromServicesAttrData } ); // 生成[FromBody]特性的数据 var fromBodyAttrData = CustomAttributeData.GetCustomAttributeData(new FromBodyAttribute()); // 创建带[FromBody]标记的body参数 var bodyParam = Expression.MakeParameter( typeof(LoginDto), "body", false, new[] { fromBodyAttrData } ); // 创建无特性的CancellationToken参数 var ctParam = Expression.Parameter(typeof(CancellationToken), "ct"); // 构建Lambda执行体:sender.Send(new LoginQuery(body), ct) var loginQueryInstance = Expression.New(typeof(LoginQuery).GetConstructor(new[] { typeof(LoginDto) })!, bodyParam); var sendCall = Expression.Call( senderParam, typeof(ISender).GetMethod(nameof(ISender.Send), new[] { typeof(object), typeof(CancellationToken) })!, loginQueryInstance, ctParam ); // 生成并编译Lambda表达式 var lambda = Expression.Lambda<Func<ISender, LoginDto, CancellationToken, Task<object>>>( sendCall, senderParam, bodyParam, ctParam ); var func = lambda.Compile();
关键说明
CustomAttributeData.GetCustomAttributeData()可以直接从特性实例提取所需数据,无需手动构造CustomAttributeData,简化代码。Expression.MakeParameter()的第四个参数支持传入多个CustomAttributeData实例,可为单个参数标记多个特性。- 用这种方式生成的Lambda参数会携带对应的特性标记,完全满足动态生成Minimal API端点的需求,能有效合并端点层与CQRS层,减少重复样板代码。
内容的提问来源于stack exchange,提问作者Massimiliano Kraus
相关产品推荐
相关产品推荐

