Узнав больше о стандартной модели событий в .NET, я обнаружил, что перед введением обобщений в С# метод, который будет обрабатывать событие, представлен этим типом делегата:
//
// Summary:
// Represents the method that will handle an event that has no event data.
//
// Parameters:
// sender:
// The source of the event.
//
// e:
// An object that contains no event data.
public delegate void EventHandler(object sender, EventArgs e);
Но после того, как дженерики были введены в С# 2, я думаю, что этот тип делегата был переписан с использованием дженериков:
//
// Summary:
// Represents the method that will handle an event when the event provides data.
//
// Parameters:
// sender:
// The source of the event.
//
// e:
// An object that contains the event data.
//
// Type parameters:
// TEventArgs:
// The type of the event data generated by the event.
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
У меня есть два вопроса здесь:
Во-первых, почему параметр типа TEventArgs не был сделан контравариантным?
Если я не ошибаюсь, рекомендуется сделать параметры типа, которые отображаются в качестве формальных параметров в сигнатуре делегата, противоречивыми, а параметр типа, который будет возвращаемым типом в коварианте сигнатуры делегата.
В книге Джозефа Албахари, С# в двух словах, я цитирую:
Если вы определяете универсальный тип делегата, рекомендуется:
- Отметьте параметр типа, используемый только для возвращаемого значения, как ковариантный (out).
- Отметьте любые типы параметров, используемые только для параметров, как контравариантные (в).
Это позволяет преобразованиям работать естественным образом, уважая отношения наследования между типами.
Второй вопрос: почему не было общего ограничения для обеспечения того, что TEventArgs наследуется от System.EventArgs?
Следующее:
public delegate void EventHandler<TEventArgs> (object source, TEventArgs e) where TEventArgs : EventArgs;
Заранее спасибо.
Отредактировано, чтобы уточнить второй вопрос:
Похоже, что общее ограничение для TEventArgs (где TEventArgs: EventArgs) существовало ранее и было удалено Microsoft, так что команда разработчиков, похоже, поняла, что это не имеет большого практического смысла.
Я отредактировал свой ответ, включив в него некоторые скриншоты из