Automatically Registering All Implementations of a Generic Interface

c#, dependency-injection, unity-container

Solution

A bit painful, but I finally pieced it together via googling and debugging:

Registration:

    IEnumerable<Type> handlers = types.Where(t => IsAssignableToGenericType(t, typeof(IDomainEventHandler<>)) && !t.IsInterface);

    foreach (var handler in handlers)
    {
        container.AddNewExtension<OpenGenericExtension>()
                    .Configure<IOpenGenericExtension>()
                    .RegisterClosedImpl(typeof (IDomainEventHandler<>), handler);
    }

IsAssignableToGenericType method:

    private static bool IsAssignableToGenericType(Type givenType, Type genericType)
    {
        var interfaceTypes = givenType.GetInterfaces();

        foreach (var it in interfaceTypes)
        {
            if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
                return true;
        }

        if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
            return true;

        Type baseType = givenType.BaseType;
        if (baseType == null) return false;

        return IsAssignableToGenericType(baseType, genericType);
    }

And the Extension. Note that if I didn't use a name for the registration, only one type would remain registered. I believe this is by design?

public interface IOpenGenericExtension : IUnityContainerExtensionConfigurator
{
    void RegisterClosedImpl(Type openGenericInterface, Type closedType);
}

public class OpenGenericExtension : UnityContainerExtension, IOpenGenericExtension
{
    protected override void Initialize() {}

    public void RegisterClosedImpl(Type openGenericInterface, Type closedType)
    {
        closedType.GetInterfaces().Where(x => x.IsGenericType)
                  .Where(x => x.GetGenericTypeDefinition() == openGenericInterface)
                  .ToList()
                  .ForEach(x => Container.RegisterType(x, closedType, closedType.Name));
    }
}

Problem

My current registration code: ``` Assembly web = Assembly.Load("MyAssembly"); types.AddRange(web.GetTypes()); //etc. foreach (var theInterface in types.Where(t => t.IsInterface)) { var assignableType = types.Where(t => theInterface.IsAssignableFrom(t) && t != theInterface); foreach (var type in assignableType) { container.RegisterType(theInterface, type); } } ``` My generic interface and its implementations: ``` public interface IDomainEventHandler<in T> { void Handle(T message); } public class DomainEventHandler1 : IDomainEventHandler<PhilTest1> { public void Handle(PhilTest1 message) { throw new System.NotImplementedException(); } } public class DomainEventHandler2 : IDomainEventHandler<PhilTest2> { public void Handle(PhilTest2 message) { throw new System.NotImplementedException(); } } public class DomainEventHandler3 : IDomainEventHandler<PhilTest2> { public void Handle(PhilTest2 message) { throw new System.NotImplementedException(); } } public class PhilTest1 { } public class PhilTest2 { } ``` Here is a simplified version of how I would resolve: ``` IEnumerable<IDomainEventHandler<PhilTest2>> listeners = Container.ResolveAll<IDomainEventHandler<PhilTest2>>(); IEnumerable<IDomainEventHandler<PhilTest1>> listeners2 = Container.ResolveAll<IDomainEventHandler<PhilTest1>>(); ``` This doesn't work--listeners and listeners2 are both empty after resolving. This is not unexpected. In Windsor, I could do something like this: ``` container.Register(AllTypes.FromAssemblyNamed("MyAssembly").BasedOn(typeof(IDomainEventHandler<>)).WithService.Base()); ``` How would I register all instances of IDomainEventHandler in Unity? I'd prefer to keep the existing registration code intact (if possible).

Original source