ссылка на требуемый перегруженный универсальный метод - PullRequest
12 голосов
/ 26 февраля 2009

дано

public Class Example
{

public static void Foo< T>(int ID){}

public static void Foo< T,U>(int ID){}

}

Вопросы:

  1. Правильно ли называть это "перегруженным универсальным методом"?
  2. Как любой метод может быть указан при создании объекта MethodInfo?

    Type exampleType = Type.GetType("fullyqualifiednameOfExample, namespaceOfExample");
    MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null);
    

аргумент 4 вызывает большое недовольство компилятора

Ответы [ 5 ]

12 голосов
/ 26 февраля 2009

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

Помните, что вам нужно вызвать MakeGenericMethod, прежде чем вы сможете его использовать.

var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
    mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
    MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
    Example example= new Example();
    closedMi.Invoke(example, new object[] { 5 });
}
3 голосов
/ 26 февраля 2009

Вот ответы на ваши вопросы вместе с примером:

  1. Да, хотя здесь есть две вещи, которые нужно учитывать при работе с общими методами: вывод типов и разрешение методов перегрузки. Вывод типа происходит во время компиляции, прежде чем компилятор пытается разрешить перегруженные сигнатуры методов. Компилятор применяет логику логического вывода ко всем универсальным методам с одинаковыми именами. На этапе разрешения перегрузки компилятор включает только те обобщенные методы, для которых вывод типа выполнен успешно. Подробнее здесь ...

  2. Пожалуйста, посмотрите полный пример программного кода Консольного приложения ниже, который показывает, как несколько вариантов метода Foo могут быть указаны при создании объекта MethodInfo и затем вызваны с использованием метода Extension:

Program.cs

class Program
{
    static void Main(string[] args)
    {
        MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string) },
            new[] { typeof(int) },
            typeof(void));

        MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string), typeof(int) },
            new[] { typeof(int) },
            typeof(void));

        MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string) },
            new[] { typeof(string) },
            typeof(void));

        MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string), typeof(int) },
            new[] { typeof(int), typeof(string) },
            typeof(string));

        Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
        Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
        Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
        Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
    }
}

Example.cs:

public class Example
{
    public static void Foo<T>(int ID) { }
    public static void Foo<T, U>(int ID) { }
    public static void Foo<T>(string ID) { }
    public static string Foo<T, U>(int intID, string ID) { return ID; }
}

Extensions.cs:

public static class Extensions
{
    public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
    {
        MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                           where m.Name == name &&
                           m.GetGenericArguments().Length == genericArgTypes.Length &&
                           m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
                           m.ReturnType == returnType
                           select m).Single().MakeGenericMethod(genericArgTypes);

        return foo1;
    }
}
1 голос
/ 06 февраля 2012

Лучше:

Пример попытки получить правильную перегрузку System.Linq.Enumerable.Select

    private static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
    {
        return ((MethodCallExpression)expression.Body).Method;
    }

    public static void CallSelect()
    {
        MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition();
        definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) });
    }
0 голосов
/ 22 апреля 2009

Я делаю небольшую модификацию вашего лямбда-запроса.

Когда тип параметра si generic, вы должны сделать так:

Я добавляю pi.ParameterType.GetGenericTypeDefinition()

и

(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)

Таким образом, метод работает очень хорошо

MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                         where m.Name == name
                         && m.GetGenericArguments().Length == genericArgTypes.Length
                         && m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
                         (returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
                         select m).FirstOrDefault();
      if (foo1 != null)
      {
        return foo1.MakeGenericMethod(genericArgTypes);
      }
      return null;

Пример:

С модификацией метода я могу вызвать этот метод расширения

public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)

С моим новым помощником вот так

var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>)); 

Подпись моего помощника

   public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
0 голосов
/ 26 февраля 2009

Вот один вкладыш Linq для того, что вам нужно:

MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...