Search code examples
c#castle-windsoropen-generics

Castle Windsor: Conditional registration of open generic types


I have the following:

class Repository<T> : IRepository<T>
interface ISuperRepository<T> : IRepository<T>
class SuperRepository<T> : ISuperRepository<T>
interface ISuperType

I want conditional registration in Castle Windsor DI for IRepository<T>, if T is ISuperType, then provide ISuperRepository<T>. Else, provide IRepository<T>.

So for example, if A : ISuperType, then I want Resolve<IRepository<A>> to provide SuperRepository<A>, and Resolve<IRepository<B>> to provide Repository<B>.

How can I achive that?


Solution

  • Castle Windsor doesn't support such a thing, however you can achieve it with a simple helper method:

    public static void RegisterAccordingToISuperType<T>(this IWindsorContainer container)
    {
        if (typeof (T).GetInterfaces().Contains(typeof (ISuperType)))
            container.Register(Component.For<IRepository<T>>()
                                        .ImplementedBy<SuperRepository<T>>());
        else
            container.Register(Component.For<IRepository<T>>()
                                        .ImplementedBy<Repository<T>>());
    }
    

    Then the registration:

    container.RegisterAccordingToISuperType<SuperType>();
    container.RegisterAccordingToISuperType<int>();
    

    And the resolve will:

    var super = container.Resolve<IRepository<SuperType>>();
    var intRepo = container.Resolve<IRepository<int>>();
    

    Another option is to the extra parameter in Component.For. Then gets all type which inherite form the Type(For example) and register them.

    private static void Register(...)
    {
        foreach (var type in GetInheriteTypes())
        {          
            container.Register(Component.For(typeof(IRepository<>),type)
                                        .ImplementedBy(typeof(SuperRepository<>)));
        }
        container.Register(Component.For(typeof(IRepository<>))
                                    .ImplementedBy(typeof(Repository<>)));
    }
    
    private static IEnumerable<Type> GetInheriteTypes()
    {
        var listOfBs = (from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
                        from assemblyType in domainAssembly.GetTypes()
                        where assemblyType.GetInterfaces().Contains(typeof(ISuperType))
                        select assemblyType).ToArray();
        return listOfBs;
    }