我试图在通用静态方法上使用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是通用的。
答案 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 等。
无论如何你不直接使用参数名称。