Подтвердить что ты не робот

Как вызвать метод расширения с помощью отражения?

Я понимаю, что подобные вопросы заданы раньше, но я изо всех сил пытаюсь вызвать метод Linq Где в следующем коде. Я хочу использовать отражение для динамического вызова этого метода, а также динамически строить делегат (или лямбда), используемый в предложении Где. Это короткий пример кода, который после работы поможет сформировать часть интерпретируемой 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;
    }
4b9b3361

Ответ 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();

        }
    }
}

Ответ 2

Методы расширения - это действительно просто статические методы под водой. Метод расширения, называемый foo.Frob(аргументы), на самом деле просто SomeClass.Frob(foo, arguments). В случае метода Where вы ищете System.Linq.Enumerable.Where. Так что получите typeof Enumerable и вызовите Where on that.

Ответ 3

Я немного устарел и поздно, но это может помочь вам, если вам нужно вызвать Linq-расширения IEnumerable, тип которых не известен.

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

то, возможно, проверить obj, если не null и

int count = test.Count()

для меня это работало очень хорошо.

Ответ 4

Ваш образец кода немного запутан... если MyObject не является перечислимым.

Используя отражение, вам нужно будет вызывать Where on System.Linq.Enumerable, передавая в перечислимом, что вы хотите преформировать Where on.

Ответ 5

Способы расширения - это трюк компилятора С#, и они не существуют в соответствующем типе. Они (эти конкретные) существуют в статических классах в пространствах имен System.Linq. Я бы предложил отразить это в рефлекторе, а затем вызвать отражение этих типов.