Меня спровоцировал этот вопрос SO о поддержке ковариации и контравариантности (.NET 4.0) для Autofac, и теперь я пытаюсь добиться чего-то подобного, но без при удаче.
Я пытаюсь настроить Autofac таким образом, чтобы при разрешении одного конкретного IEventHandler
(для демонстрации с использованием container.Resolve
, но обычно, конечно, с использованием внедрения конструктора) Autofac вернет мне MultipleDispatchEventHandler
, который охватывает все зарегистрированные обработчики событий, которые могут быть назначены из запрошенного обработчика.
Другими словами, когда я пишу это:
var handler = container
.GetInstance>();
handler.Handle(new CustomerMovedEvent());
Что касается дизайна приложения (приведенного ниже), я ожидал, что будет возвращен MultipleDispatchEventHandler
, который обертывает оба CustomerMovedEventHandler
и NotifyStaffWhenCustomerMovedEventHandler
.
Вот дизайн приложения:
// Events:
public class CustomerMovedEvent { }
public class CustomerMovedAbroadEvent : CustomerMovedEvent { }
public class SpecialCustomerMovedEvent : CustomerMovedEvent { }
// Event handler definition (note the 'in' keyword):
public interface IEventHandler
{
void Handle(TEvent e);
}
// Event handler implementations:
public class CustomerMovedEventHandler
: IEventHandler
{
public void Handle(CustomerMovedEvent e) { ... }
}
public class NotifyStaffWhenCustomerMovedEventHandler
: IEventHandler
{
public void Handle(CustomerMovedEvent e) { ... }
}
public class CustomerMovedAbroadEventHandler
: IEventHandler
{
public void Handle(CustomerMovedAbroadEvent e) { ... }
}
Это определение MultipleDispatchEventHandler
, определенного в корне композиции:
// A composite wrapping possibly multiple handlers.
public class MultipleDispatchEventHandler
: IEventHandler
{
private IEnumerable> handlers;
public MultipleDispatchEventHandler(
IEnumerable> handlers)
{
this.handlers = handlers;
}
public void Handle(TEvent e)
{
this.handlers.ToList().ForEach(h => h.Handle(e));
}
}
Это моя текущая конфигурация:
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();
С текущей конфигурации приложение не работает во время вызова Resolve
со следующим исключением:
Autofac.Core.DependencyResolutionException: круговой компонент обнаружена зависимость: MultipleDispatchEventHandler'1 [[SpecialCustomerMovedEvent]] -> IEventHandler'1 [[SpecialCustomerMovedEvent]] [] -> MultipleDispatchEventHandler'1 [[SpecialCustomerMovedEvent]].
Теперь, конечно же, возникает вопрос: как я могу исправить конфигурацию (или дизайн), чтобы поддержать это?