gpt4 book ai didi

c# - 如何在运行时才知道类型时创建 Expression.Lambda?

转载 作者:可可西里 更新时间:2023-11-01 07:54:35 25 4
gpt4 key购买 nike

这最好用代码来解释。我有一个泛型类,它有一个返回整数的方法。这是一个简单的版本,用于解释...

public class Gen<T>
{
public int DoSomething(T instance)
{
// Real code does something more interesting!
return 1;
}
}

在运行时,我使用反射来发现某物的类型,然后想为该特定类型创建我的 Gen 类的实例。这很容易,像这样完成......

Type fieldType = // This is the type I have discovered
Type genericType = typeof(Gen<>).MakeGenericType(fieldType);
object genericInstance = Activator.CreateInstance(genericType);

我现在想创建一个表达式,它将一个泛型实例作为参数,然后调用该类型的 DoSomething 方法。所以我希望表达式能够有效地执行此...

int answer = genericInstance.DoSomething(instance);

...除了在运行时稍后的某个时间我没有“实例”,并且 genericInstance 是生成的类型,如上所示。我为此创建 Lambda 的尝试如下...

MethodInfo mi = genericType.GetMethod("DoSomething", 
BindingFlags.Instance | BindingFlags.Public);

var p1 = Expression.Parameter(genericType, "generic");
var p2 = Expression.Parameter(fieldType, "instance");

var x = Expression.Lambda<Func<genericType, fieldType, int>>
(Expression.Call(p1, mi, p2),
new[] { p1, p2 }).Compile();

...以便稍后我可以用这样的方式调用它...

int answer = x(genericInstance, instance);

当然,您不能为 Func 提供实例参数,所以我不知道如何参数化 Lambda 生成。有什么想法吗?

最佳答案

我想你会使用 Expression.Lambda它将委托(delegate)类型作为类型而不是泛型,并像使用 Gen<> 一样即时创建 Func :

MethodInfo mi = genericType.GetMethod("DoSomething",
BindingFlags.Instance | BindingFlags.Public);

var p1 = Expression.Parameter(genericType, "generic");
var p2 = Expression.Parameter(fieldType, "instance");
var func = typeof (Func<,,>);
var genericFunc = func.MakeGenericType(genericType, fieldType, typeof(int));
var x = Expression.Lambda(genericFunc, Expression.Call(p1, mi, p2),
new[] { p1, p2 }).Compile();

这将返回一个委托(delegate)而不是强类型 Func , 但你当然可以在需要时转换它(如果你不知道你要转换到什么看起来很困难),或者使用 DynamicInvoke 动态调用它在上面。

int answer = (int) x.DynamicInvoke(genericInstance, instance);

编辑:

A good idea that does indeed work. Unfortunately the reason I want to use a strongly typed compiled Lambda is performance. Using DynamicInvoke is prettty slow compared to a typed Lambda.

这似乎不需要动态调用就可以工作。

var p1 = Expression.Parameter(genericType, "generic");
var p2 = Expression.Parameter(fieldType, "instance");
var func = typeof(Func<,,>);
var genericFunc = func.MakeGenericType(genericType, fieldType, typeof(int));
var x = Expression.Lambda(genericFunc, Expression.Call(p1, mi, p2), new[] { p1, p2 });
var invoke = Expression.Invoke(x, Expression.Constant(genericInstance), Expression.Constant(instance));
var answer = Expression.Lambda<Func<int>>(invoke).Compile()();

编辑 2:

一个大大简化的版本:

Type fieldType = ;// This is the type I have discovered
Type genericType = typeof(Gen<>).MakeGenericType(fieldType);
object genericInstance = Activator.CreateInstance(genericType);
MethodInfo mi = genericType.GetMethod("DoSomething",
BindingFlags.Instance | BindingFlags.Public);
var value = Expression.Constant(instance, fieldType);
var lambda = Expression.Lambda<Func<int>>(Expression.Call(Expression.Constant(genericInstance), mi, value));
var answer = lambda.Compile()();

关于c# - 如何在运行时才知道类型时创建 Expression.Lambda?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7801165/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com