c# - 如何使用反射调用扩展方法?

标签 c# linq reflection delegates lambda

我明白以前有人问过类似的问题,但我很难在下面的代码中调用 Linq Where 方法。我希望使用反射来动态调用此方法,并动态构建 Where 子句中使用的委托(delegate)(或 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 对通用类型有一些限制,因此您必须使用搜索找到实际的类型。

找到方法后,您必须使用 MakeGenericMethod 调用使 MethodInfo 变得具体。

这是一个完整的工作示例:

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();

        }
    }
}

关于c# - 如何使用反射调用扩展方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1452261/

相关文章:

c# - 泛型协变转换或转换为实型

C# 反射 : providing T for a generic method

c# - SQL中的隐式数据类型转换会影响性能吗?

c# - EF - LINQ to Entities 不支持

C# WPF 应用程序首先打开常规 Windows 窗体

VB.Net LINQ - 两个数据表之间的左外连接 - 限制为一行

c# - 确定集合至少有 2 个项目的有效方法

c# - Linq 左连接多个表

c# - 控制 C# 中的中心面板滚动

c# - 转换通过反射创建的类时遇到问题