代码之家  ›  专栏  ›  技术社区  ›  Jon Simpson

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

  •  29
  • Jon Simpson  · 技术社区  · 16 年前

    我很感激以前也有人问过类似的问题,但我一直在努力地求助于LINQ。 在哪里? 方法。我希望使用反射来动态调用此方法,并动态构建中使用的委托(或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;
        }
    
    5 回复  |  直到 11 年前
        1
  •  44
  •   toddmo    11 年前

    正如其他人所说,扩展方法是编译器的魔法,你可以一直使用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();
    
            }
        }
    }
    
        2
  •  10
  •   Joren    12 年前

    扩展方法实际上只是水下的静态方法。像foo.frob这样的扩展方法调用( 争论 )真的只是一个班级。frob(foo, 争论 )。在Where方法的情况下,您要查找System.Linq.Enumerable.Where。因此,获取可枚举的类型并在其上调用Where。

        3
  •  2
  •   Jens Marchewka    13 年前

    我有点晚了,但是如果你需要调用一个不知道的IEnumerable wich类型的linq扩展,这可以帮助你。

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

    如果不为空,则可能测试obj

    int count = test.Count()

    对我来说,这很管用。

        4
  •  1
  •   Will    16 年前

    您的代码示例有点混乱…除非myObject是可枚举的。

    使用反射,您必须调用System.Linq.Enumerable上的Where,并传入要在何处执行的Enumerable。

        5
  •  0
  •   Preet Sangha    16 年前

    扩展方法是一种C编译器技巧,它们不存在于相关类型中。它们(这些特定的类)存在于system.linq名称空间中的静态类中。我建议在Reflector中反射这个,然后调用这些类型的反射。