我有一个接受object
类型参数的表达式。我需要使用Type
变量在运行时创建一个类型化表达式。见下文。该参数应为int
类型,以便最终得到Expression<Action<Program, int>>
,其中给定的int
调用非类型Set
方法。怎么办呢?
class Program
{
private static Type SomeRuntimeType() => typeof(int);
public void Set(object v)
{
Debug.WriteLine("Setting value...");
}
static void Main(string[] args)
{
Expression<Action<Program, object>> e1 = (t, v) => t.Set(v);
var type = SomeRuntimeType();
// TODO: Create typed expression...
Expression<Action<Program, type>> e2 = ...
}
}
答案 0 :(得分:2)
简单解决方案:从C#角度来看,Lambda Expression是无类型的(类型为LambdaExpression
)。在运行时它是“正确的类型”(如Expression<Action<Program, T2>>
,这是可能的,因为Expression<T>
子类LambdaExpression
)
Expression<Action<Program, object>> e1 = (t, v) => t.Set(v);
var type = typeof(int);
var par1 = e1.Parameters[0];
var par2 = Expression.Parameter(type);
// if type is a value type, you have to expressly box it
Expression conv = type.IsValueType ? (Expression)Expression.Convert(par2, typeof(object)) : par2;
// We "chain" the two expressions
InvocationExpression invoke = Expression.Invoke(e1, par1, conv);
LambdaExpression lambda = Expression.Lambda(invoke, par1, par2);
var compiled = lambda.Compile();
// sanity check,
bool lambdaTypeIsExpected = typeof(Expression<>).MakeGenericType(typeof(Action<,>).MakeGenericType(typeof(Program), type)) == lambda.GetType();
请注意,如果某些ORM或其他子系统需要LambdaExpression
,则并非所有库都支持Invoke
(可以使用表达式重写器删除)或Convert
(从值类型转换为引用类型是必要的)。我甚至看过那些不喜欢object
全程停止的图书馆(我已经尝试了不同时间的这些技巧:-))