Autofac: Скрытие нескольких контравариантных реализаций за одним составным элементом

Меня спровоцировал этот вопрос 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]].

Теперь, конечно же, возникает вопрос: как я могу исправить конфигурацию (или дизайн), чтобы поддержать это?

14
задан Community 23 May 2017 в 11:52
поделиться