ссылка на желаемый перегруженный универсальный метод

данный

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 вызывает у компилятора большое неудовольствие

Ответов (6)

Решение

Я не могу найти способ использования 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 });
}

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

MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);

Я немного изменил ваш лямбда-запрос.

Когда тип параметра 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)

Лучше:

Пример попытки получить правильную перегрузку 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)) });
    }

Еще один лайнер для поиска нужного MethodInfo вам - создание делегата;

var methodInfo = new Action<int>(Example.Foo<object,object>).Method.GetGenericMethodDefinition();

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

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

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

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;
    }
}