如何使用反射调用扩展方法? [英] How do I invoke an extension method using reflection?

查看:28
本文介绍了如何使用反射调用扩展方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很感激之前有人问过类似的问题,但我很难在以下代码中调用 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();

        }
    }
}

这篇关于如何使用反射调用扩展方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆