如何将Expression<Action<T, object>>转换为Expression<Action<T, U>>?
实现运行时强类型表达式树构建
要解决这个问题,核心是利用表达式树API动态构建强类型委托,同时完成强类型参数到object的隐式转换,适配Set方法的参数要求。下面是具体的实现步骤和完整代码:
核心思路
我们需要手动拼接表达式树的各个节点:
- 定义表达式的两个输入参数:
Program实例,以及指定运行时类型的参数 - 将强类型参数转换为
object类型(适配Set方法的参数要求,值类型会自动完成装箱) - 构建调用
Set方法的表达式节点 - 最后把这些节点组合成强类型的
Expression<Action<Program, T>>(其中T是SomeRuntimeType()返回的类型)
完整代码实现
using System; using System.Linq.Expressions; using System.Diagnostics; class Program { private static Type SomeRuntimeType() => typeof(int); public void Set(object v) { Debug.WriteLine($"Setting value: {v}"); } static void Main(string[] args) { Expression<Action<Program, object>> e1 = (t, v) => t.Set(v); var targetType = SomeRuntimeType(); // 1. 获取Set方法的元信息 var setMethod = typeof(Program).GetMethod(nameof(Set), new[] { typeof(object) }); // 2. 定义表达式的两个输入参数 var programParam = Expression.Parameter(typeof(Program), "t"); var valueParam = Expression.Parameter(targetType, "v"); // 3. 将强类型参数转换为object(自动处理值类型装箱) var convertedValue = Expression.Convert(valueParam, typeof(object)); // 4. 构建调用Set方法的表达式节点 var callExpr = Expression.Call(programParam, setMethod, convertedValue); // 5. 动态创建强类型的Expression<Action<Program, T>> var lambdaGenericType = typeof(Expression<>).MakeGenericType( typeof(Action<,>).MakeGenericType(typeof(Program), targetType) ); var e2 = (LambdaExpression)Activator.CreateInstance( lambdaGenericType, callExpr, new[] { programParam, valueParam } ); // 测试:编译并执行表达式 var action = (Delegate)e2.Compile(); action.DynamicInvoke(new Program(), 123); } }
关键细节说明
- 获取方法元信息:通过反射拿到
Set方法的MethodInfo,这是构建方法调用表达式的基础 - 参数定义:用
Expression.Parameter定义表达式的输入参数,第二个参数是参数的名称(可自定义) - 类型转换处理:
Expression.Convert会自动处理值类型的装箱操作,引用类型则直接完成类型转换,完美适配Set方法的object参数 - 动态强类型表达式:因为
targetType是运行时确定的,所以需要通过MakeGenericType动态创建Expression<Action<Program, T>>的类型,再用反射完成实例化
这样构建出来的e2就是你需要的强类型表达式,编译后可以直接传入对应类型的参数调用Set方法。
内容的提问来源于stack exchange,提问作者l33t
相关产品推荐
相关产品推荐

