В приведенном ниже коде показан общий класс с типом ограничения (Pub<T>
). У класса есть событие, которое он может повысить, что позволяет нам передавать сообщение подписчикам. Ограничение состоит в том, что сообщение должно реализовать IMsg
(или наследовать от IMsg
, когда оно является абстрактным классом).
Pub<T>
также предоставляет метод Subscribe
, позволяющий объектам подписываться на событие notify
тогда и только тогда, когда объект реализует IHandler<IMsg>
.
Используя .NET 4, приведенный ниже код показывает ошибку на baseImplementer.NotifyEventHandler
, в которой указано, что: "No overload for 'IHandler<IMsg>.NotifyEventHandler(IMsg)' matches delegate 'System.Action<T>'"
Вопрос: (с обновленным методом Subscribe)
Почему ошибка исчезает, как только я меняю "IMsg" на абстрактный класс вместо интерфейса?
public interface IMsg { } // Doesn't work
//public abstract class IMsg { } // Does work
public class Msg : IMsg { }
public class Pub<T> where T : IMsg
{
public event Action<T> notify;
public void Subscribe(object subscriber)
{
// Subscriber subscribes if it implements IHandler of the exact same type as T
// This always compiles and works
IHandler<T> implementer = subscriber as IHandler<T>;
if (implementer != null)
this.notify += implementer.NotifyEventHandler;
// If subscriber implements IHandler<IMsg> subscribe to notify (even if T is Msg because Msg implements IMsg)
// This does not compile if IMsg is an interface, only if IMsg is an abstract class
IHandler<IMsg> baseImplementer = subscriber as IHandler<IMsg>;
if (baseImplementer != null)
this.notify += baseImplementer.NotifyEventHandler;
}
}
public interface IHandler<T> where T : IMsg
{
void NotifyEventHandler(T data);
}
Ниже приведен код ниже, чтобы воспроизвести проблему... но показывает, как использовать приведенный выше код. Очевидно, что IMsg
(и производные классы Msg
) будут определять или реализовывать методы, которые можно было бы вызвать в обработчике.
public class SubA : IHandler<Msg>
{
void IHandler<Msg>.NotifyEventHandler(Msg data) { }
}
public class SubB : IHandler<IMsg>
{
void IHandler<IMsg>.NotifyEventHandler(IMsg data) { }
}
class MyClass
{
Pub<Msg> pub = new Pub<Msg>();
SubA subA = new SubA();
SubB subB = new SubB();
public MyClass()
{
//Instead of calling...
this.pub.notify += (this.subA as IHandler<Msg>).NotifyEventHandler;
this.pub.notify += (this.subB as IHandler<IMsg>).NotifyEventHandler;
//I want to call...
this.pub.Subscribe(this.subA);
this.pub.Subscribe(this.subB);
//...except that the Subscribe method wont build when IMsg is an interface
}
}