如何使用反射调用的扩展方法?(How do I invoke an extension method

2019-07-18 17:06发布

我认识到,类似的问题已经被问过,但我奋力调用的LINQ 在下面的代码的方法。 我期待使用反射动态调用此方法,也动态地构建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;
    }

Answer 1:

正如有人说,扩展方法是编译器的魔力,可以送花儿给人使用VS点击右键,转到定义找到实现静态方法真正的类型。

从那里,它变得相当毛Where超载,所以你需要找到你想要的签名相匹配的实际定义。 GetMethod与泛型类型的一些限制,所以你必须找到使用搜索的实际之一。

一旦你找到了方法,你必须做出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();

        }
    }
}


Answer 2:

扩展方法实际上只是静态方法水下。 像foo.Frob( 参数 )的扩展方法调用实际上只是SomeClass.Frob(FOO, 参数 )。 在Where方法的情况下,你正在寻找System.Linq.Enumerable.Where。 所以得到的typeof可枚举并调用哪里上。



Answer 3:

我是有点过,晚,但是这可能会帮助你,如果你需要调用一个IEnumerable的至极类型的LINQ的扩展是未知。

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

那么也许判断obj如果不是零和

int count = test.Count()

对于我这种工作非常出色。



Answer 4:

你的代码示例是有点混乱......除非myObject的是一个枚举。

使用反射,你必须调用凡System.Linq.Enumerable,传递枚举你想在哪里瓶坯。



Answer 5:

Extention方法是C#编译器的伎俩,他们不关心中的类型存在。 他们(这些特定的)在System.Linq的名称空间内静态类存在。 我建议在反射反映这一点,然后对这些类型的调用的反映。



文章来源: How do I invoke an extension method using reflection?