Получить общий метод без использования GetMethods

Я хочу получить метод System.Linq.Queryable.OrderyBy(the IQueryable source, Expression<Func> keySelector) , но я продолжаю придумывать нули.

 var type = typeof(T); var propertyInfo = type.GetProperty(group.PropertyName); var propertyType = propertyInfo.PropertyType; var sorterType = typeof(Func).MakeGenericType(type, propertyType); var expressionType = typeof(Expression).MakeGenericType(sorterType); var queryType = typeof(IQueryable); var orderBy = typeof(System.Linq.Queryable).GetMethod("OrderBy", new[] { queryType, expressionType }); /// is always null. 

У кого-нибудь есть понимание? Я бы предпочел не проходить через результат GetMethods .

9 Solutions collect form web for “Получить общий метод без использования GetMethods”

Решено (взломать LINQ)!

Я видел ваш вопрос, исследуя ту же проблему. Не найдя хорошего решения, у меня возникла идея взглянуть на дерево выражений LINQ. Вот что я придумал:

 public static MethodInfo GetOrderByMethod() { Func fakeKeySelector = element => default(TSortKey); Expression, IOrderedEnumerable>> lamda = list => list.OrderBy(fakeKeySelector); return (lamda.Body as MethodCallExpression).Method; } static void Main(string[] args) { List ints = new List() { 9, 10, 3 }; MethodInfo mi = GetOrderByMethod(); Func keySelector = i => i.ToString(); IEnumerable sortedList = mi.Invoke(null, new object[] { ints, keySelector } ) as IEnumerable; foreach (int i in sortedList) { Console.WriteLine(i); } } 

мощность: 10 3 9

EDIT: вот как получить метод, если вы не знаете тип во время компиляции:

 public static MethodInfo GetOrderByMethod(Type elementType, Type sortKeyType) { MethodInfo mi = typeof(Program).GetMethod("GetOrderByMethod", Type.EmptyTypes); var getOrderByMethod = mi.MakeGenericMethod(new Type[] { elementType, sortKeyType }); return getOrderByMethod.Invoke(null, new object[] { }) as MethodInfo; } 

Обязательно замените typeof (Program) на typeof (WhateverClassYouDeclareTheseMethodsIn).

Вариант вашего решения в качестве метода расширения:

 public static class TypeExtensions { private static readonly Func> ParameterTypeProjection = method => method.GetParameters() .Select(p => p.ParameterType.GetGenericTypeDefinition()); public static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes) { return (from method in type.GetMethods() where method.Name == name where parameterTypes.SequenceEqual(ParameterTypeProjection(method)) select method).SingleOrDefault(); } } 

Я думаю, что следующий метод расширения будет решением проблемы:

 public static MethodInfo GetGenericMethod( this Type type, string name, Type[] generic_type_args, Type[] param_types, bool complain = true) { foreach (MethodInfo m in type.GetMethods()) if (m.Name == name) { ParameterInfo[] pa = m.GetParameters(); if (pa.Length == param_types.Length) { MethodInfo c = m.MakeGenericMethod(generic_type_args); if (c.GetParameters().Select(p => p.ParameterType).SequenceEqual(param_types)) return c; } } if (complain) throw new Exception("Could not find a method matching the signature " + type + "." + name + "< " + String.Join(", ", generic_type_args.AsEnumerable()) + ">" + "(" + String.Join(", ", param_types.AsEnumerable()) + ")."); return null; } 

Вызов будет похож на (просто изменив последнюю строку исходного кода):

 var type = typeof(T); var propertyInfo = type.GetProperty(group.PropertyName); var propertyType = propertyInfo.PropertyType; var sorterType = typeof(Func< ,>).MakeGenericType(type, propertyType); var expressionType = typeof(Expression<>).MakeGenericType(sorterType); var queryType = typeof(IQueryable); var orderBy = typeof(Queryable).GetGenericMethod("OrderBy", new Type[] { type, propertyType }, new[] { queryType, expressionType }); 

В отличие от других решений: результирующий метод точно соответствует типам параметров, а не только их базовым типам.

Я не верю, что есть простой способ сделать это – это в основном недостающая функция от размышлений, IIRC. Вам нужно пройти через методы, чтобы найти тот, который вы хотите 🙁

 var orderBy = (from methodInfo in typeof(System.Linq.Queryable).GetMethods() where methodInfo.Name == "OrderBy" let parameterInfo = methodInfo.GetParameters() where parameterInfo.Length == 2 && parameterInfo[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>) && parameterInfo[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>) select methodInfo ).Single(); 

Если вы знаете типы во время компиляции, вы можете сделать это с меньшим количеством кода без использования типа выражения или в зависимости от Linq вообще:

 public static MethodInfo GetOrderByMethod() { IEnumerable col = null; return new Func, IOrderedEnumerable>(col.OrderBy).Method; } 

Используя lambda-выражения, вы можете легко получить общий метод

  var method = type.GetGenericMethod (c => c.Validate((IValidator)this, o, action)); 

Об этом подробнее здесь:

http://www.nerdington.com/2010/08/calling-generic-method-without-magic.html

http://web.archive.org/web/20100911074123/http://www.nerdington.com/2010/08/calling-generic-method-without-magic.html

Я думаю, что это будет сделано с таким classом:

 public static class SortingUtilities { public static IOrderedQueryable ApplyOrderBy(IQueryable query, Expression> selector) { return query.OrderBy(selector); } public static IOrderedQueryable ApplyOrderByDescending(IQueryable query, Expression> selector) { return query.OrderByDescending(selector); } public static IQueryable Preload(IQueryable query, Expression> selector) { return query.Include(selector); } } 

И вы можете использовать это даже так:

 public class SortingOption where T: class { private MethodInfo ascendingMethod; private MethodInfo descendingMethod; private LambdaExpression lambda; public string Name { get; private set; } public SortDirection DefaultDirection { get; private set; } public bool ApplyByDefault { get; private set; } public SortingOption(PropertyInfo targetProperty, SortableAttribute options) { Name = targetProperty.Name; DefaultDirection = options.Direction; ApplyByDefault = options.IsDefault; var utilitiesClass = typeof(SortingUtilities< ,>).MakeGenericType(typeof(T), targetProperty.PropertyType); ascendingMethod = utilitiesClass.GetMethod("ApplyOrderBy", BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase); descendingMethod = utilitiesClass.GetMethod("ApplyOrderByDescending", BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase); var param = Expression.Parameter(typeof(T)); var getter = Expression.MakeMemberAccess(param, targetProperty); lambda = Expression.Lambda(typeof(Func< ,>).MakeGenericType(typeof(T), targetProperty.PropertyType), getter, param); } public IQueryable Apply(IQueryable query, SortDirection? direction = null) { var dir = direction.HasValue ? direction.Value : DefaultDirection; var method = dir == SortDirection.Ascending ? ascendingMethod : descendingMethod; return (IQueryable)method.Invoke(null, new object[] { query, lambda }); } } 

с атрибутом вроде этого:

 public class SortableAttribute : Attribute { public SortDirection Direction { get; set; } public bool IsDefault { get; set; } } 

и это перечисление:

 public enum SortDirection { Ascending, Descending } 

Еще один комментарий (это должно быть, но с тех пор, как он слишком длинный, я должен опубликовать его как ответ), следуя за ответом @NeilWhitaker -s (здесь, используя Enumerable.Count), поскольку мы находимся в середине очистки строк: ) почему бы не использовать деревья выражений в методе bytype? Что-то вроде :

  #region Count ///  /// gets the /// public static int Count<TSource>(this IEnumerable<TSource> source); /// methodinfo ///  /// type of the elements ///  public static MethodInfo GetCountMethod() { Expression, int>> lamda = list => list.Count(); return (lamda.Body as MethodCallExpression).Method; } ///  /// gets the /// public static int Count<TSource>(this IEnumerable<TSource> source); /// methodinfo ///  /// type of the elements ///  public static MethodInfo GetCountMethodByType(Type elementType) { // to get the method name, we use lambdas too Expression methodNamer = () => GetCountMethod(); var gmi = ((MethodCallExpression)methodNamer.Body).Method.GetGenericMethodDefinition(); var mi = gmi.MakeGenericMethod(new Type[] { elementType }); return mi.Invoke(null, new object[] { }) as MethodInfo; } #endregion Disctinct 
  • Как программно компилировать и создавать экземпляр classа Java?
  • Можно ли создать экземпляр вложенного classа с помощью Java Reflection?
  • Как десериализация WCF создает объекты без вызова конструктора?
  • Какая польза для тегов в Go?
  • Reflection - получить имя атрибута и значение свойства
  • Создайте экземпляр объекта object-c по имени?
  • Как я могу получить все classы в пространстве имен?
  • В чем разница между System.Type и System.RuntimeType в C #?
  • Как получить общий тип во время выполнения?
  • GetMethod для общего метода
  • Как получить имя переменной с помощью отражения?
  • Давайте будем гением компьютера.