Ограничения универсального типа

171
30 апреля 2018, 23:14

Был взят за основу код из ответа на SO. Нужно была доработка класса MessageHandlerAdapter чтобы в качестве базового типа была команда ICommand<IMessage>, но при попытке собрать MessageHandlerAdapter<ICommandHandler<MyMessage>> получаю ошибку, о том что мой тип не подходит под ограничения.

var handler = typeof(MessageAdapter<>).MakeGenericType(typeof(ICommand<>).MakeGenericType(typeof(MyMessage)));

Сами типы:

public interface IMessage { }
public class MyMessage : IMessage {};
public interface ICommand<TMessage> where TMessage : IMessage {};
public class MessageAdapter<TMessageCommand> where TMessageCommand : ICommand<IMessage> { }

Вопрос: почему это происходит и как решить эту проблему? Ведь MyMessage наследует IMessage.

Зачем мне это нужно: Над классом handler будет висеть кастомный аттрибут с параметрами команды. Для варианта как у автора на SO нельзя узнать тип, который скрывается внутри лямбды, пока не вызовешь. Мой полный код.

Answer 1

Проблема в том, что наследование MyMessage от IMessage не делает вашу команду ICommand<MyMessage> наследницей ICommand<IMessage>! В этом можно убедиться вот таким простым кодом:

ICommand<MyMessage> foo = null;
ICommand<IMessage> bar = foo; // Ошибка компиляции

Для того чтобы ICommand<MyMessage> можно было приводить к типу ICommand<IMessage> - нужно сделать интерфейс ICommand<> ковариантынм:

public interface ICommand<out TMessage> where TMessage : IMessage {};

К сожалению, на ковариантные интерфейсы наложены сильные ограничения, и для команды такой вариант скорее всего не подойдет. В таком случае придется делать ваш MessageAdapter знающим не только тип команды, но и тип сообщения:

public class MessageAdapter<TMessage, TCommand> 
    where TMessage : IMessage
    where TCommand : ICommand<TMessage> { }
READ ALSO
Примеры сверточных нейронных сетей

Примеры сверточных нейронных сетей

Где можно найти полноценные примеры сверточных нейронных сетей для C# без применения сторонних библиотек?

178
Проблема при расширении свойств класса

Проблема при расширении свойств класса

Создаю обёртку над SortedDictionary

185
Ошибка использования using(void method())

Ошибка использования using(void method())

Не могу понять ошибки в строке - using(TimerStart())

121
WCF - Рассылка сообщений сервером

WCF - Рассылка сообщений сервером

Клиенты должны получать сообщение(одинаковое), которое рассылается с сервера, как можно это реализовать? Понимаю когда клиент может получать...

154