问题描述
我很感激之前有人问过类似的问题,但我很难在以下代码中调用 Linq Where 方法.我希望使用反射来动态调用此方法,并动态构建 Where 子句中使用的委托(或 lambda).这是一个简短的代码示例,一旦工作,将有助于形成我正在构建的解释型 DSL 的一部分.干杯.
I appreciate that similar questions have been asked before, but I am struggling to invoke the Linq Where method in the following code. I am looking to use reflection to dynamically call this method and also dynamically build the delegate (or lambda) used in the Where clause. This is a short code sample that, once working, will help to form part of an interpreted DSL that I am building. Cheers.
public static void CallWhereMethod()
{
List<MyObject> myObjects = new List<MyObject>(){new MyObject{Name="Jon Simpson"}};
System.Delegate NameEquals = BuildEqFuncFor<MyObject>("Name", "Jon Simpson");
object[] atts = new object[1] ;
atts[0] = NameEquals;
var ret = typeof(List<MyObject>).InvokeMember("Where", BindingFlags.InvokeMethod, null, InstanceList,atts);
}
public static Func<T, bool> BuildEqFuncFor<T>(string prop, object val)
{
return t => t.GetType().InvokeMember(prop,BindingFlags.GetProperty,
null,t,null) == val;
}
推荐答案
正如其他人所说,扩展方法是编译器的魔法,你总是可以使用 VS 右键单击,转到定义找到实现静态方法的真正类型.
As others said, extensions methods are compiler magic, you can alway use VS right click, go to definition to find the real type that implements the static method.
从那里,它变得相当多毛.Where
被重载了,所以你需要找到与你想要的签名匹配的实际定义.GetMethod
对泛型类型有一些限制,因此您必须使用搜索找到实际的类型.
From there, it gets fairly hairy. Where
is overloaded, so you need to find the actual definition that matches the signature you want. GetMethod
has some limitations with generic types so you have to find the actual one using a search.
找到方法后,必须使用 MakeGenericMethod
调用使 MethodInfo
特定.
Once you find the method, you must make the MethodInfo
specific using the MakeGenericMethod
call.
这是一个完整的工作示例:
Here is a full working sample:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication9 {
class Program {
class MyObject {
public string Name { get; set; }
}
public static void CallWhereMethod() {
List<MyObject> myObjects = new List<MyObject>() {
new MyObject { Name = "Jon Simpson" },
new MyObject { Name = "Jeff Atwood" }
};
Func<MyObject, bool> NameEquals = BuildEqFuncFor<MyObject>("Name", "Jon Simpson");
// The Where method lives on the Enumerable type in System.Linq
var whereMethods = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Where");
Console.WriteLine(whereMethods.Count());
// 2 (There are 2 methods that are called Where)
MethodInfo whereMethod = null;
foreach (var methodInfo in whereMethods) {
var paramType = methodInfo.GetParameters()[1].ParameterType;
if (paramType.GetGenericArguments().Count() == 2) {
// we are looking for Func<TSource, bool>, the other has 3
whereMethod = methodInfo;
}
}
// we need to specialize it
whereMethod = whereMethod.MakeGenericMethod(typeof(MyObject));
var ret = whereMethod.Invoke(myObjects, new object[] { myObjects, NameEquals }) as IEnumerable<MyObject>;
foreach (var item in ret) {
Console.WriteLine(item.Name);
}
// outputs "Jon Simpson"
}
public static Func<T, bool> BuildEqFuncFor<T>(string prop, object val) {
return t => t.GetType().InvokeMember(prop, BindingFlags.GetProperty,
null, t, null) == val;
}
static void Main(string[] args) {
CallWhereMethod();
Console.ReadKey();
}
}
}
这篇关于如何使用反射调用扩展方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!