Autofac: ocultando várias implementações contravariantes atrás de um composto
Foi acionado poresta questão SOobre o suporte a covariância e contravariância do (.NET 4.0) para Autofac, e agora estou tentando obter algo semelhante, mas sem sort
O que estou tentando alcançar é configurar o Autofac de tal maneira que, quando resolvo um únicoIEventHandler<TEvent>
(para fins de demonstração usandocontainer.Resolve
, mas normalmente, é claro, usando injeção de construtor), o Autofac retornará umMultipleDispatchEventHandler<TEvent>
que agrupa todos os manipuladores de eventos registrados atribuíveis a partir do manipulador solicitad
Em outras palavras, quando escrevo isto:
var handler = container
.GetInstance<IEventHandler<CustomerMovedEvent>>();
handler.Handle(new CustomerMovedEvent());
Com relação ao design do aplicativo (fornecido abaixo), eu esperaria umMultipleDispatchEventHandler<CustomerMovedEvent>
a ser retornado que envolve umCustomerMovedEventHandler
eNotifyStaffWhenCustomerMovedEventHandler
.
qui está o design do aplicativo:
// Events:
public class CustomerMovedEvent { }
public class CustomerMovedAbroadEvent : CustomerMovedEvent { }
public class SpecialCustomerMovedEvent : CustomerMovedEvent { }
// Event handler definition (note the 'in' keyword):
public interface IEventHandler<in TEvent>
{
void Handle(TEvent e);
}
// Event handler implementations:
public class CustomerMovedEventHandler
: IEventHandler<CustomerMovedEvent>
{
public void Handle(CustomerMovedEvent e) { ... }
}
public class NotifyStaffWhenCustomerMovedEventHandler
: IEventHandler<CustomerMovedEvent>
{
public void Handle(CustomerMovedEvent e) { ... }
}
public class CustomerMovedAbroadEventHandler
: IEventHandler<CustomerMovedAbroadEvent>
{
public void Handle(CustomerMovedAbroadEvent e) { ... }
}
Esta é a definição deMultipleDispatchEventHandler<TEvent>
, definido na Raiz da composição:
// A composite wrapping possibly multiple handlers.
public class MultipleDispatchEventHandler<TEvent>
: IEventHandler<TEvent>
{
private IEnumerable<IEventHandler<TEvent>> handlers;
public MultipleDispatchEventHandler(
IEnumerable<IEventHandler<TEvent>> handlers)
{
this.handlers = handlers;
}
public void Handle(TEvent e)
{
this.handlers.ToList().ForEach(h => h.Handle(e));
}
}
Esta é minha configuração atual:
var builder = new ContainerBuilder();
// Note the use of the ContravariantRegistrationSource (which is
// available in the latest release of Autofac).
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IEventHandler<>).Assembly)
.AsClosedTypesOf(typeof(IEventHandler<>));
// UPDATE: I'm registering this last as Kramer suggests.
builder.RegisterGeneric(typeof(MultipleDispatchEventHandler<>))
.As(typeof(IEventHandler<>)).SingleInstance();
var container = builder.Build();
Com a configuração atual, o aplicativo falha durante a chamada paraResolve
, com a seguinte exceção:
Autofac.Core.DependencyResolutionException: Dependência de componente circular detectada: MultipleDispatchEventHandler'1 [[SpecialCustomerMovedEvent]] -> IEventHandler'1 [[SpecialCustomerMovedEvent]] [] -> MultipleDispatchEventHandler'1 [[SpecialCustomerMovedEvent
gora, a questão é clara: como posso corrigir a configuração (ou o design) para suportar iss