如何将表达式<Action<T, object>> 转换为表达式<Action<T, U>>?
How to convert Expression<Action<T, object>> to Expression<Action<T, U>>?
我有一个接受 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 = ...
}
}
简单的解决方案:从 C# 的角度来看,Lambda 表达式是无类型的(它的类型是 LambdaExpression
)。在运行时它属于 "right type"(如 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
句号的库(我已经多次尝试过这些技巧 :-) )
我有一个接受 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 = ...
}
}
简单的解决方案:从 C# 的角度来看,Lambda 表达式是无类型的(它的类型是 LambdaExpression
)。在运行时它属于 "right type"(如 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
句号的库(我已经多次尝试过这些技巧 :-) )