Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

autofac Resolve all types of open generic type?

Tags:

c#

autofac

I'm guessing there is no way to do something like the following with Autofac, to ctor inject an enumerable collection of open generic types? The various Handle types have dependencies, otherwise I would just dynamically build those up.

    class EventOne : IEvent {...}
    class EventTwo : IEvent {...}
    class EventThree : IEvent {...}
    interface IHandleEvent<T> where T : IEvent {...}
    class HandleEventOne : IHandleEvent<EventOne> {...}
    class HandleEventTwo : IHandleEvent<EventTwo> {...}
    class HandleEventThree : IHandleEvent<EventThree> {...}

    builder.RegisterAssemblyTypes(myAssembies).AsClosedTypesOf(typeof(IHandleEvent<>));
    builder.RegisterType<AService>().As<IAService>();


    class AService : IAService
    {
      public AService(IEnumerable<IHandleEvent<IEvent>> handles)
      {...}
    }
like image 551
Suedeuno Avatar asked Apr 05 '16 19:04

Suedeuno


1 Answers

As explained in the comments, what you want is impossible to achieve in C# and with good reason. If you were able to cast an IHandleEvent<EventOne> to an IHandleEvent<IEvent> it would allow an EventTwo to be passed in as well, which would fail at runtime.

So what you need is an mediator abstraction that allow getting all the compatible event handlers and call them. Such mediator is often called IEventPublisher and might look like this:

public interface IEventPublisher {
    void Publish(IEvent e);
}

You can now create a container specific implementation. For instance, for Autofac this would look as follows:

public class AutofacEventPublisher : IEventPublisher {
    private readonly IComponentContext container;

    public AutofacBusinessRuleValidator(IComponentContext container) {
        this.container = container;
    }

    public void Publish(IEvent e) {
        foreach (dynamic handler in this.GetHandlers(e.GetType())) {
            handler.Handle((dynamic)e);
        }
    }

    private IEnumerable GetHandlers(Type eventType) =>
        (IEnumerable)this.container.Resolve(
            typeof(IEnumerable<>).MakeGenericType(
                typeof(IHandleEvent<>).MakeGenericType(eventType)));
}

Consumers can now depend on this new abstraction:

class AService : IAService
{
    public AService(IEventPublisher publisher) {...}
}
like image 200
Steven Avatar answered Oct 12 '22 22:10

Steven