Search code examples
c#genericsdependency-injectioncastle-windsoraspnetboilerplate

Register multiple implementations of generic interface in Castle Windsor


I want to register an implementation for my service IQueryService<TEntity, TPrimaryKey>.

So I have code that looks like this:

IocManager.IocContainer.Register(Component.For(typeof(IQueryService<,>))
    .ImplementedBy(typeof(QueryService<,,,>);

And I want to create a similar implementation for entities with string as primary key, let's call it QueryServiceString. Is there a way to write it down so that Castle Windsor will automatically pick up which class it should inject?

IocManager.IocContainer.Register(Component.For(typeof(IQueryService<,STRING?>))
    .ImplementedBy(typeof(QueryServiceString<,,>)

Solution

  • A partially open generic type IQueryService<,STRING?> is invalid syntax.

    You can register a factory method and resolve a type based on the generic arguments:

    IocManager.IocContainer.Register(Component.For(typeof(QueryService<,>)));
    IocManager.IocContainer.Register(Component.For(typeof(QueryServiceString<>)));
    
    IocManager.IocContainer.Register(Component.For(typeof(IQueryService<,>))
        .UsingFactoryMethod((kernel, creationContext) =>
        {
            Type type = null;
    
            var tEntity = creationContext.GenericArguments[0];
            var tPrimaryKey = creationContext.GenericArguments[1];
            if (tPrimaryKey == typeof(string))
            {
                type = typeof(QueryServiceString<>).MakeGenericType(tEntity);
            }
            else
            {
                type = typeof(QueryService<,>).MakeGenericType(tEntity, tPrimaryKey);
            }
    
            return kernel.Resolve(type);
        }));