Phi*_*ght 14 c# generics lambda expression-trees
最好使用代码解释.我有一个泛型类,它有一个返回整数的方法.这是一个简单的版本,用于解释......
public class Gen<T>
{
public int DoSomething(T instance)
{
// Real code does something more interesting!
return 1;
}
}
Run Code Online (Sandbox Code Playgroud)
在运行时,我使用反射来发现某事物的类型,然后想要为该特定类型创建我的Gen类的实例.这很容易,像这样完成......
Type fieldType = // This is the type I have discovered
Type genericType = typeof(Gen<>).MakeGenericType(fieldType);
object genericInstance = Activator.CreateInstance(genericType);
Run Code Online (Sandbox Code Playgroud)
我现在想要创建一个Expression,它将参数作为泛型类型的一个实例,然后调用该类型的DoSomething方法.所以我希望Expression能有效地执行此操作......
int answer = genericInstance.DoSomething(instance);
Run Code Online (Sandbox Code Playgroud)
...除了我之前在运行时某点之后没有'实例',并且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();
Run Code Online (Sandbox Code Playgroud)
......所以以后我可以用这样的东西来称它...
int answer = x(genericInstance, instance);
Run Code Online (Sandbox Code Playgroud)
当然,您无法为Func提供实例参数,因此我不知道如何参数化Lambda生成.有任何想法吗?
vcs*_*nes 20
我认为你只Expression.Lambda
需要使用委托类型作为类型而不是通用,并像你一样随时创建你的Func Gen<>
:
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();
Run Code Online (Sandbox Code Playgroud)
这将返回一个Delegate而不是一个强类型Func
,但你当然可以在需要时抛出它(如果你不知道你要投射到什么,看起来很难),或者使用它来动态调用DynamicInvoke
它.
int answer = (int) x.DynamicInvoke(genericInstance, instance);
Run Code Online (Sandbox Code Playgroud)
编辑:
确实有效的好主意.不幸的是,我想使用强类型编译的Lambda的原因是性能.与类型化的Lambda相比,使用DynamicInvoke非常慢.
这似乎无需动态调用即可工作.
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()();
Run Code Online (Sandbox Code Playgroud)
编辑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()();
Run Code Online (Sandbox Code Playgroud)