"in" указывает на разницу, верно?
Да.
Это означает, что если API ожидает чего-то более общего, вы можете передатьэто что-то более конкретное (в моей базе «ISomeInterface» будет общим, а мой «SomeDerivedClass» будет конкретным).
Нет.Контравариантность делегата позволяет делегату ссылаться на метод с типами параметров, которые являются менее производными, чем в типе делегата.Например, предположим, что ISomeInterface
имеет базовый интерфейс:
interface ISomeBaseInterface
{
}
interface ISomeInterface : ISomeBaseInterface
{
}
И предположим, что handler
занял ISomeBaseInterface
вместо SomeDerivedClass
:
static void handler(object sender, ISomeBaseInterface e)
Тогда new SomeClass().SomeEvent += handler
будетработа.
Вот почему исходный код не является безопасным типом: когда SomeClass
повышает SomeEvent
, он может потенциально передать что угодно , которое реализует ISomeInterface
в качестве аргумента data
,Например, он мог бы передать экземпляр SomeDerivedClass
, но он также мог бы передать экземпляр
class SomeOtherDerivedClass : ISomeInterface
{
}
. Если бы вы могли зарегистрировать void handler(object sender, SomeDerivedClass e)
с событием, этот обработчик будет вызванс SomeOtherDerivedClass
, который не работает.
Таким образом, вы можете зарегистрировать обработчики событий, которые на более общие , чем тип события, а не обработчики событий, которые более конкретны.
ОБНОВЛЕНИЕ: Вы прокомментировали:
Ну, на самом деле я хочу перебрать список и проверить типы.Поэтому, если событие должно было быть запущено с объектом данных типа, скажем, SomeOtherDerivedObject, тогда программа будет перебирать список методов, которые подписаны на событие, пока не найдет тот, который соответствует сигнатуре (объект, SomeOtherDerivedObject).Таким образом, само событие будет использоваться только для хранения, а не для фактического вызова делегатов.
Я не думаю, что C # позволяет вам объявить event
, который работает с произвольными типами делегатов.Вот как вы можете написать методы, которые добавляют обработчики событий и вызывают их:
class SomeClass
{
private Delegate handlers;
public delegate void SomeEventDelegate<in T>(object sender, T data);
public void AddSomeEventHandler<T>(SomeEventDelegate<T> handler)
{
this.handlers = Delegate.Combine(this.handlers, handler);
}
protected void OnSomeEvent<T>(T data)
{
if (this.handlers != null)
{
foreach (SomeEventDelegate<T> handler in
this.handlers.GetInvocationList().OfType<SomeEventDelegate<T>>())
{
handler(this, data);
}
}
}
}