You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让C#动态构建的Lambda表达式与匿名类型表达式输出一致?

动态构建表达式树生成编译器风格匿名类型实例化的解决方案

要让动态构建的Expression<Func<TestTable, object>>生成和手动编写一致的、带编译器自动命名(如<>f__AnonymousType02`)的匿名类型实例化表达式,核心是要引用编译器实际生成的匿名类型,或者动态生成同格式的密封类型,而不是仅构建语法层面的匿名类型初始化节点。以下是两种可行方案:

方案一:复用编译器生成的匿名类型(简单高效)

先手动创建一个与目标字段列表匹配的匿名类型实例,获取其真实类型,再基于该类型构建表达式树:

// 1. 创建匹配字段的匿名类型实例,获取编译器生成的真实类型
var sampleAnonymous = new { KeyID = default(int), KeyID2 = default(int) };
Type anonymousType = sampleAnonymous.GetType();

// 2. 构建参数表达式(对应lambda的输入参数e)
ParameterExpression param = Expression.Parameter(typeof(TestTable), "e");

// 3. 获取匿名类型的构造函数和属性成员
ConstructorInfo ctor = anonymousType.GetConstructors().First();
PropertyInfo[] props = anonymousType.GetProperties();

// 4. 构建属性绑定:将TestTable的属性映射到匿名类型的属性
MemberBinding[] bindings = props.Select(prop => 
    Expression.Bind(prop, Expression.Property(param, prop.Name))
).ToArray();

// 5. 创建匿名类型实例化表达式,注意要传入构造函数、属性绑定和属性列表
NewExpression newExpr = Expression.New(ctor, bindings.Select(b => ((MemberAssignment)b).Expression), props);

// 6. 构建最终的lambda表达式,添加装箱转换(因为返回值是object)
Expression<Func<TestTable, object>> lambda = Expression.Lambda<Func<TestTable, object>>(
    Expression.Convert(newExpr, typeof(object)),
    param
);

此方案直接复用了C#编译器自动生成的<>f__AnonymousTypeXN`类型,生成的表达式与手动编写的示例1完全一致。

方案二:动态生成同格式的匿名类型(完全动态场景)

如果无法提前构造匿名类型实例(字段列表完全动态),可以通过Reflection.Emit动态生成符合编译器命名规范的密封类,再基于该类构建表达式树:

using System.Reflection;
using System.Reflection.Emit;

// 定义动态字段列表(key是字段名,value是字段类型)
var dynamicFields = new Dictionary<string, Type> { { "KeyID", typeof(int) }, { "KeyID2", typeof(int) } };

// 1. 创建动态程序集与模块
var assemblyName = new AssemblyName("DynamicAnonymousTypes");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);

// 2. 生成编译器风格的匿名类型名称:<>f__AnonymousType{序号}`{泛型参数数}
int typeSequence = 0; // 可根据需要递增避免重复
int propertyCount = dynamicFields.Count;
string typeName = $"<>f__AnonymousType{typeSequence}`{propertyCount}";

// 3. 定义密封类(与编译器生成的匿名类型属性一致:public sealed)
TypeBuilder typeBuilder = moduleBuilder.DefineType(
    typeName,
    TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit
);

// 4. 为每个字段生成私有字段+公共属性
List<Type> ctorParamTypes = new();
List<PropertyBuilder> propBuilders = new();

foreach (var (propName, propType) in dynamicFields)
{
    // 定义私有字段(编译器生成的匿名类型字段格式为<属性名>i__Field)
    FieldBuilder fieldBuilder = typeBuilder.DefineField($"<{propName}>i__Field", propType, FieldAttributes.Private);
    
    // 定义公共属性
    PropertyBuilder propBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.None, propType, null);
    
    // 生成属性的get方法
    MethodBuilder getMethod = typeBuilder.DefineMethod(
        $"get_{propName}",
        MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
        propType,
        Type.EmptyTypes
    );
    ILGenerator getIl = getMethod.GetILGenerator();
    getIl.Emit(OpCodes.Ldarg_0);
    getIl.Emit(OpCodes.Ldfld, fieldBuilder);
    getIl.Emit(OpCodes.Ret);
    propBuilder.SetGetMethod(getMethod);
    
    propBuilders.Add(propBuilder);
    ctorParamTypes.Add(propType);
}

// 5. 生成构造函数,为私有字段赋值
ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor(
    MethodAttributes.Public,
    CallingConventions.Standard,
    ctorParamTypes.ToArray()
);
ILGenerator ctorIl = ctorBuilder.GetILGenerator();
for (int i = 0; i < dynamicFields.Count; i++)
{
    ctorIl.Emit(OpCodes.Ldarg_0);
    ctorIl.Emit(OpCodes.Ldarg, i + 1);
    ctorIl.Emit(OpCodes.Stfld, typeBuilder.GetField($"<{dynamicFields.Keys.ElementAt(i)}>i__Field"));
}
ctorIl.Emit(OpCodes.Ret);

// 6. 完成动态类型创建
Type dynamicAnonymousType = typeBuilder.CreateType();

// 7. 基于动态类型构建表达式树
ParameterExpression param = Expression.Parameter(typeof(TestTable), "e");
ConstructorInfo ctor = dynamicAnonymousType.GetConstructors().First();
var ctorArgs = dynamicFields.Select(kv => Expression.Property(param, kv.Key)).ToArray();
PropertyInfo[] props = dynamicAnonymousType.GetProperties();

NewExpression newExpr = Expression.New(ctor, ctorArgs, props);
Expression<Func<TestTable, object>> lambda = Expression.Lambda<Func<TestTable, object>>(
    Expression.Convert(newExpr, typeof(object)),
    param
);

此方案生成的类型完全模拟编译器的匿名类型格式,表达式输出与示例1一致,适合字段列表完全动态的场景。


内容的提问来源于stack exchange,提问作者Jeremy Miedreich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:10:31