我可以在Generic和Static方法上使用Expression.Call吗?

时间:2015-10-16 13:52:40

标签: linq c#-4.0

我试图在通用静态方法上使用Expression.Call。 不幸的是,Call Method没有签名允许给出泛型类型参数和方法信息参数。

这可能是以任何方式吗?

我具体尝试的是编写一个可以动态地通过Linq对IEnumerable(DataRow)进行排序的辅助类。

不幸的是,我必须使用DataRowExtensions来获取我想要在Lambda表达式中排序的字段。

原始代码来自http://aonnull.blogspot.de/2010/08/dynamic-sql-like-linq-orderby-extension.html

(实验性的)代码片段如下所示:

//T is DataRow
Type type = typeof(T);            

IEnumerable<MethodInfo> extensions = GetExtensionMethods(Assembly.GetAssembly(typeof(DataRowExtensions)), typeof(DataRow));
ParameterExpression arg = Expression.Parameter(typeof(DataRow), "x");

//at Position 0 there is T Field<T>(string)   
MethodInfo mi = extensions.ToList()[0];

var methArg = Expression.Parameter(typeof(String), "\"" + orderByInfo + "\"");                              
MethodCallExpression expr = Expression.Call(null, mi, arg, methArg);                          
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), typeof(Object));
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

当Runtime到达Expression.Call语句时,会抛出异常,说Field-Method是通用的。

1 个答案:

答案 0 :(得分:3)

所以,是的。当您获得 Field 方法的 MethodInfo 时,您确实获得了泛型方法,而没有指定返回值的类型。

T Field<T>(string)

要解决此问题,只需使用此方法中的MakeGenericMethod和所需类型,例如

MethodInfo mi = extensions.ToList()[0].MakeGenericMethod(typeof(object));

此处mi已经指定了通用参数和当前功能

object Field(string);

此外,您的代码有点复杂,所以您可以稍微简化它并得到类似的东西

//T is DataRow
Type type = typeof(T);            

IEnumerable<MethodInfo> extensions = GetExtensionMethods(Assembly.GetAssembly(typeof(DataRowExtensions)), type);//if T is DataRow not needed get typeof again

ParameterExpression arg = Expression.Parameter(typeof(DataRow), "x");

//at Position 0 there is T Field<T>(string)   
MethodInfo mi = extensions.ToList()[0].MakeGenericMethod(typeof(object));//you can change object type to needed type

var methArg = Expression.Parameter(typeof(String), orderByInfo);//if orderByInfo already string, then not needed wrap it in quotes

LambdaExpression lambda = Expression.Lambda<Func<T,string,object>>(
    Expression.Call(mi, arg, methArg), //call mi with args: arg, methArg
    arg,methArg);//pass parameters

Sidenote :您无法为参数指定名称,在这种情况下,名称将自动生成,例如: Param_0 Param_1 等。
无论如何你不直接使用参数名称。