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

Как я могу программным образом разрешить перегрузку метода в С#?

Когда компилятор С# интерпретирует вызов метода, он должен использовать (статические) типы аргументов, чтобы определить, какая перегрузка действительно вызывается. Я хочу иметь возможность делать это программно.

Если у меня есть имя метода (a string), тип, который его объявляет (экземпляр System.Type), и список типов аргументов, я хочу иметь возможность вызвать стандартную библиотечную функцию и верните объект MethodInfo, представляющий метод, с которым будет ссылаться компилятор С#.

Например, если у меня есть

class MyClass {
  public void myFunc(BaseClass bc) {};
  public void myFunc(DerivedClass dc) {};
}

Тогда я хочу что-то вроде этой вымышленной функции GetOverloadedMethod на System.Type

MethodInfo methodToInvoke
  = typeof(MyClass).GetOverloadedMethod("myFunc", new System.Type[] {typeof(BaseClass)});

В этом случае methodToInvoke должен быть public void myFunc(BaseClass bc).

ПРИМЕЧАНИЕ: Ни один из методов GetMethod и GetMethods не будет служить моей цели. Ни один из них не имеет никакого разрешения перегрузки. В случае GetMethod он возвращает только точные совпадения. Если вы дадите ему более производные аргументы, он просто ничего не вернет. Или вам может посчастливиться получить исключение двусмысленности, которое не предоставляет никакой полезной информации.

4b9b3361

Ответ 1

Ответ

Используйте Type.GetMethod(String name, Type[] types) для выполнения программной перегрузки. Вот пример:

MethodInfo methodToInvoke = typeof(MyClass)
    .GetMethod("myFunc", new System.Type[] { typeof(BaseClass) });

Объяснение

В примере methodToInvoke будет myFunc(BaseClass bc) not myFunc(DerivedClass dc), потому что массив types указывает список параметров метода для получения.

Из документации MSDN Type.GetMethod(String name, Type[] types) имеет два параметра:

  • name - это имя метода для получения, а
  • types содержит порядок, число и типы параметров метода.

Код запуска

Вот бег скрипта, демонстрирующий программное разрешение перегрузки.

using System;
using System.Reflection;

public static class Program
{
    public static void Main()
    {
        MethodInfo methodToInvoke = typeof(MyClass)
            .GetMethod("myFunc", new System.Type[] { typeof(BaseClass) });

        var result = methodToInvoke
            .Invoke(new MyClass(), new object[] { new BaseClass() });

        Console.WriteLine(result);      
    }

    public class MyClass
    {
        public static string myFunc(BaseClass bc) {
            return "BaseClass";
        }

        public static string myFunc(DerivedClass dc) {
            return "DerivedClass";
        }
    }

    public class BaseClass { }
    public class DerivedClass : BaseClass { }
}

Выходной сигнал BaseClass.

Изменить: это надежный.

GetMethod разрешенные методы, которые принимают params, более производные классы, делегаты и реализации интерфейса. Этот скрипт демонстрирует все эти случаи. Вот призывы и то, что они получают.

Работает с params

MethodInfo methodToInvoke2 = typeof(MyClass).GetMethod(
        "myFunc",
        new System.Type[] { typeof(Int32[]) });

разрешит этот метод

public static string myFunc(params int[] i)
{
    return "params";
}

Работает с более производными классами

MethodInfo methodToInvoke3 = typeof(MyClass).GetMethod(
    "myFunc", 
    new System.Type[] { typeof(MoreDerivedClass) });

разрешает метод, который принимает значение MoreDerivedClass

public class BaseClass { }
public class DerivedClass : BaseClass { }
public class MoreDerivedClass : DerivedClass {}

Работает с делегатами

MethodInfo methodToInvoke4 = typeof(MyClass).GetMethod(
    "myFunc", 
    new System.Type[] { typeof(MyDelegate) });

... извлечет метод, который принимает этот делегат:

public delegate void MyDelegate(string x);

Работает с реализациями интерфейса

MethodInfo methodToInvoke5 = typeof(MyClass).GetMethod(
   "myFunc", 
   new System.Type[] { typeof(MyImplementation) });

... успешно извлекает метод, который принимает MyImplementation

public interface IMyInterface {}
public class MyImplementation : IMyInterface {}

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