Невозможно назначить обработчик событий, который использует производный тип для EventArgs в c # - PullRequest
0 голосов
/ 22 апреля 2019

Итак, у меня есть событие, объявленное следующим образом:

public event EventHandler OnChangeDetected;

Затем у меня есть следующий обработчик, который назначается этому событию.

myObject.OnChangeDetected += OnTableChanged;

Насколько я понимаю, этот типсобытие потребовало бы, чтобы мой метод OnTableChanged имел следующую подпись, которая прекрасно компилируется.

public void OnTableChanged(object sender, EventArgs e)

Теперь я хочу заменить событие OnTableChanged следующей подписью.

public void OnTableChanged(SqlChangeNotifier sender, SqlNotificationEventArgs e)

Однако,Когда я заменяю параметры производными типами, он жалуется, что нет перегрузки для «OnTableChanged», который соответствует делегату EventHandler.Поскольку SqlChangeNotifier является производным от Object, а SqlNotificationEventArgs является производным от EventArgs, может кто-нибудь объяснить, почему у меня не может быть этих производных типов параметров, поскольку они наследуются от правильных базовых типов?

Ответы [ 3 ]

1 голос
/ 22 апреля 2019

EventHandler является делегатом типа void EventHandler(object sender, EventArgs e). Таким образом, подпись обработчиков, которые подписываются на событие, должна соответствовать этому.

Теперь void OnTableChanged(SqlChangeNotifier sender, SqlNotificationEventArgs e) более конкретен: он больше не может принимать любой sender объект, и аргументы события также должны иметь тип SqlNotificationEventArgs.

Проблема заключается в том, что при возникновении события исходный отправитель события пытается вызвать обработчики событий с аргументами object sender, EventArgs e, но для вашего метода требуются более специализированные типы. Система типов не гарантирует, что эти аргументы на самом деле относятся к этим специализированным типам.

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

0 голосов
/ 22 апреля 2019

Общую тему об изменениях такого рода см. В Contravariance and Covariance .

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

Как и методы, обработчики событий являются противоречивымиЭто означает, что delagate типа EventHandler<SpecializedEventArgs> (при условии SpecializedEventArgs : EventArgs) будет принимать обработчик подписи public void Handler(object sender, EventArgs args), потому что вызов события заканчивается вызовом обработчика с объектом SpecializedEventArgs, который может быть неявно преобразован в EventArgs простым полиморфизмом.IE компилирует следующее:

public static event EventHandler<SpecializedEventArgs> Event;
public static void Handler(object sender, EventArgs args) { }

public static void Main() {
    Event += Handler;
//...
0 голосов
/ 22 апреля 2019

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

Вам разрешено делать все наоборот:

public static event KeyEventHandler ChangeDetected; // handler with derived args signature

private static void Program_ChangeDetected(object sender, EventArgs e) // base event args are OK
{
    Console.WriteLine("ChangeDetected");
}

static void Main(string[] args)
{
    ChangeDetected += Program_ChangeDetected;
    ChangeDetected?.Invoke(null, new KeyEventArgs(default)); // base event args are NOT OK
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...