В приведенном ниже коде показан общий класс с типом ограничения (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
}
}