我感谢以前曾问过类似的问题,但是我在以下代码中努力调用Linq Where 方法。我希望使用反射来动态调用此方法,并动态构建 Where 子句中使用的委托(或lambda)。这是一个简短的代码示例,一旦运行,将有助于形成我正在构建的已解释DSL的一部分。干杯。
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右键单击,转到定义以查找实现静态方法的真实类型。
从那里开始,它变得很 毛茸茸 。Where重载,因此您需要找到与所需签名匹配的实际定义。GetMethod泛型类型有一些限制,因此您必须使用搜索找到实际的类型。
Where
GetMethod
找到方法后,必须MethodInfo使用该MakeGenericMethod调用进行特定设置。
MethodInfo
MakeGenericMethod
这是一个完整的工作示例:
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(); } } }