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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1452261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 17:41:07  来源:igfitidea点击:

How do I invoke an extension method using reflection?

c#linqreflectiondelegateslambda

提问by Jon Simpson

I appreciate that similar questions have been asked before, but I am struggling to invoke the Linq Wheremethod 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 Whereclause. This is a short code sample that, once working, will help to form part of an interpreted DSL that I am building. Cheers.

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

采纳答案by Sam Saffron

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.

正如其他人所说,扩展方法是编译器魔术,您可以随时使用VS右键单击,转到定义找到实现静态方法的真实类型。

From there, it gets fairly hairy. Whereis overloaded, so you need to find the actual definition that matches the signature you want. GetMethodhas some limitations with generic types so you have to find the actual one using a search.

从那里,它变得相当多毛Where重载,因此您需要找到与您想要的签名匹配的实际定义。GetMethod泛型类型有一些限制,因此您必须使用搜索找到实际的类型。

Once you find the method, you must make the MethodInfospecific using the MakeGenericMethodcall.

找到方法后,您必须MethodInfo使用MakeGenericMethod调用进行特定操作。

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

        }
    }
}

回答by Preet Sangha

Extention methods are a c# compiler trick, and they don't exist in the type concerned. They (these particular ones) exist in static classes within the System.Linq name spaces. I'd suggest reflecting this in reflector and then invoking reflection on these types.

扩展方法是 ac# 编译器技巧,它们不存在于相关类型中。它们(这些特定的)存在于 System.Linq 名称空间内的静态类中。我建议在反射器中反映这一点,然后对这些类型进行反射。

回答by Joren

Extension methods are really just static methods underwater. An extension method call like foo.Frob(arguments) is really just SomeClass.Frob(foo, arguments). In the case of the Where method, you're looking for System.Linq.Enumerable.Where. So get the typeof Enumerable and invoke Where on that.

扩展方法实际上只是水下的静态方法。像 foo.Frob( arguments)这样的扩展方法调用实际上只是 SomeClass.Frob(foo, arguments)。在 Where 方法的情况下,您正在寻找 System.Linq.Enumerable.Where。因此,获取 typeof Enumerable 并调用 Where 。

回答by Joren

Your code sample is a little confusing... unless MyObject is an enumerable.

您的代码示例有点令人困惑……除非 MyObject 是可枚举的。

Using reflection you'll have to invoke Where on System.Linq.Enumerable, passing in the enumerable you want to preform Where on.

使用反射,您必须调用 System.Linq.Enumerable 上的 Where,传入您想要执行 Where on 的枚举。

回答by Jens Marchewka

I'm a bit off and late but this could help you if you need to call Linq extensions of a IEnumerable wich type is unkown.

我有点晚了,但是如果您需要调用 IEnumerable 类型未知的 Linq 扩展,这可以帮助您。

IEnumerable<dynamic> test = obj as IEnumerable<dynamic>;

IEnumerable<dynamic> test = obj as IEnumerable<dynamic>;

then maybe test obj if not null and

然后也许测试 obj 如果不是 null 和

int count = test.Count()

int count = test.Count()

for me that worked very well.

对我来说效果很好。