2012-06-19 2 views
2

Я работаю над приложением с использованием MEF (в частности, MEF 2 Preview 5), и у меня возникла проблема с попыткой импорта на основе общих интерфейсов.MEF - ImportMany с общими интерфейсами и Lazy <T, TMetadata>

У меня есть интерфейс:

public interface IMessageHandler<in T> 
{ 
    void HandleMessage(T message); 
} 

, где Т представляет собой тип сообщения, которое будет обрабатываться. Я импортировать эти вещи в каталог с помощью RegistrationBuilder:

RegistrationBuilder context = new RegistrationBuilder(); 

context.ForTypesDerivedFrom(typeof(IMessageHandler<>)) 
    .Export(builder => builder.AsContractType(typeof(IMessageHandler<>))); 

, а затем, в классе, потребляющего я использую [ImportMany] импортировать список этих в IEnumerable<Lazy>>:

[ImportMany(typeof(IMessageHandler<>))] 
IEnumerable<Lazy<IMessageHandler<object>, HandledMessageTypeAttribute>> _messageHandlers; 

сейчас , здесь первая проблема - вы вынуждены назначать тип для общего интерфейса в этот момент. Я использую Lazy<T, TMetadata>, поскольку версии IMessageHandler<T> имеют соответствующие метаданные, которые я хочу использовать (HandledMessageTypeAttribute).

Теперь, когда я хочу, чтобы получить доступ к любому элементу в IEnumerable<Lazy<>> коллекции я получаю следующее исключение:

Cannot cast the underlying exported value of type 
'MessageHandlerImplementation (ContractName="IMessageHandler(System.Object)")' 
to type 'IMessageHandler`1[System.Object]'. 

Я понимаю (примерно), почему я получаю исключение, проблема, я понятия не имею, как обойти это. Итак, в основном, что я хочу сделать:

  1. Имейте кучу классов, которые реализуют интерфейс IMessageHandler<T>.
  2. Попросите их обнаружить во время работы с MEF.
  3. Импортируйте их в коллекцию, которая позволяет мне потреблять любые метаданные, которые у них есть.
  4. Уметь создавать их.

Я понимаю, что я мог бы просто сделать IMessageHandler нетипичными и имею IMessageHandler.HandleMessage() принимает параметр типа object, но я искал немного более элегантное решение

Любые указатели или инструктивный ценюсь.

ответ

3

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

public interface IMessageHandler<in T> 

, что означает, что если у нас есть два класса, A и B, где B происходит от A, то это разрешено

IMessageHandler<B> handler = new AHandler(); 

, но это не:

IMessageHandler<A> handler = new BHandler(); 

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

public IMessageHandler GetHandler<T>() 
{ 
    Type handlerType = typeof(T); 
    return _messageHandlers.FirstOrDefault(x => x.Metadata.MessageType == handlerType); 
} 

Вы можете найти this question соответствующую а. Надеюсь это поможет.

Смежные вопросы