Delegate.CreateDelegate () создает неправильный делегат, когда несколько методов отличаются только одним параметром перечисления - PullRequest
1 голос
/ 13 марта 2019

У меня есть некоторые проблемы при создании правильных делегатов для некоторых методов моих классов.Существует базовый класс и производный класс, оба имеют метод protected object GetValue (EnumPID), но EnumPID определяется отдельно в обоих классах.Таким образом, в целом обе функции можно отличить друг от друга.
Теперь я попытался создать делегаты для этих функций, используя
Delegate.CreateDelegate (Type, object, string),
, потому что new <delegate-name>(function) не работает, так как function не является общедоступным.
Ошибка состоит в том, что оба делегата, созданные с помощью Delegate.CreateDelegate(), указывают на одну и ту же функцию, которая является производной от класса.

Чтобы упростить это, вот тестовый класс.Я обнаружил, что нет необходимости использовать наследование, оно может быть воспроизведено с 2 различными перечислениями в одном классе:

public class CClass
{
  public delegate void DelegatePrint1 (Enum1 i_en1);
  public delegate void DelegatePrint2 (Enum2 i_en2);
  public delegate void DelegatePrint3 (Enum3 i_en3);

  public enum Enum1 { a = 1, b = 2 }
  public enum Enum2 { a = 99 }
  public enum Enum3 { z = 100 }

  public void Print (Enum1 i_en1) { Console.WriteLine (i_en1.ToString () + "=" + (int)i_en1); }
  public void Print (Enum2 i_en2) { Console.WriteLine (i_en2.ToString () + "=" + (int)i_en2); }
  public void Print (Enum3 i_en3) { Console.WriteLine (i_en3.ToString () + "=" + (int)i_en3); }
}

private static void Main ()
{
  string sMethod_Print = "Print";
  var oClass = new CClass ();
  var delPrint1 = (CClass.DelegatePrint1)Delegate.CreateDelegate (typeof (CClass.DelegatePrint1), oClass, sMethod_Print);
  var delPrint2 = (CClass.DelegatePrint2)Delegate.CreateDelegate (typeof (CClass.DelegatePrint2), oClass, sMethod_Print);
  var delPrint3 = (CClass.DelegatePrint3)Delegate.CreateDelegate (typeof (CClass.DelegatePrint3), oClass, sMethod_Print);
  delPrint1 (CClass.Enum1.a);
  delPrint1 (CClass.Enum1.b);
  delPrint2 (CClass.Enum2.a);
  delPrint3 (CClass.Enum3.z);
}

Ожидаемый результат -

a=1
b=2
a=99
z=100

фактический результат равен

1=1
2=2
99=99
z=100

, потому что все делегаты вызывают Print(Enum3).

Мои вопросы:
1) Как я могу создать правильный делегат?(Я уже выяснил, см. Мой собственный ответ ниже.)
2) Почему CreateDelegate (Type, object, string) создает делегата от неправильной функции?Разве данного Типа недостаточно для определения правильного?

1 Ответ

1 голос
/ 13 марта 2019

Очевидно, что конструктор делегата намного умнее, чем функция Delegate.CreateDelegate(), потому что
var del1 = new CClass.DelegatePrint1 (oClass.Print);
создает правильный делегат, но это работает, только если функция общедоступна.

Решение: вместо
Delegate.CreateDelegate (Type, object, string)
Вы должны использовать
Delegate.CreateDelegate (Type, object, MethodInfo)
с MethodInfo, равным
var oMethod1 = typeof (CClass).GetMethod ("Print", new Type[] { typeof (CClass.Enum1) });
Таким образом, будет выбрана правильная перегрузка Print.

Относительно того, почему это необходимо (это мой второй вопрос), у меня нет ответа. Я проверил источник .net CreateDelegate() на https://referencesource.microsoft.com/#mscorlib/system/delegate.cs,2b489eed284b305b,, но я не совсем уверен, как он работает, потому что он вызывает внешние методы MulticastDelegate InternalAlloc(RuntimeType type) и bool BindToMethodName(Object target, RuntimeType methodType, String method, DelegateBindingFlags flags). Я предполагаю, что либо информация о типе не полностью сохраняется InternalAlloc, либо BindToMethodName принимает Enum как int.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...