Хорошо, это запрещено, потому что это небезопасно.А?Как может следующее не быть безопасным для типа:
var _handlers = new Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>>();
var loginRequestHandler = new LoginRequestHandler();
_handlers[messageId] = loginRequestHandler;
LoginRequestHandler
- это IMessageHandler<IPeerAttachment, IMessage>
, так что здесь не так?
Хорошо, допустим, что предыдущие были законными, и возьмем егошаг вперед и посмотрим, что произойдет:
var handler = _handlers[meesageId];
handler.HandleMessage(logOutPeerAttachment, logOutMessage);
Это законно?Ну, это так выглядит.handler
имеет тип IMessageHandler<IPeerAttachment, IMessage>
и поэтому HandleMessage
может обрабатывать предоставленные типы аргументов ...
Итак, теперь мы попали в ужасную ситуацию;выполнив совершенно законные шаги, мы только что нарушили систему типов, потому что почему-то мы попросили LoginRequestHandler
обработать LogOutRequest
.
Очевидно, поскольку вы испытали мучительный опыт из первых рук, не все шагизаконны;это ссылочное преобразование фактически недопустимо: (IMessageHandler<IPeerAttachment, IMessage>)loginRequestHandler
Чтобы это преобразование работало, дисперсия типа IMessageHandler
должна быть ковариантной, что означает, что универсальные аргументы могут только выходить, а не в (это немного более замысловато, чем это, но это передает идею).Канонический пример?IEnumerable<out T>
?Зачем?Поскольку невозможно ввести T
в IEnumerable<T>
, поэтому это допустимо:
var tigers = new List<Tiger>();
IEnumerable<Animal> animals = tigers;
Но это не так:
var tigers = new List<Tiger>();
List<Animal> animals = tigers;
В вашем сценарииковариантный интерфейс, кажется, не является выбором, поэтому вам, вероятно, нужно пересмотреть свой подход.Похоже, вы пытаетесь выразить слишком много в своей системе типов до такой степени, что она борется с вами.