简体   繁体   中英

Castle windsor resolve array with open generic and interface

I would like to resolve the following with castle windsor:

IEnumerable<Definition<IEntity>>

At the moment I'm only getting an IEnumerable with 1 object which matches the first implementation of IEntity.

I would like an array of

{ Definition<Entity1>, Definition<Entity2>, ... } 

I have a feeling a sub resolver is needed but I have no idea where to start.

Update

var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(
     new CollectionResolver(container.Kernel, true));

container.Register(Component.For(typeof (Definition<>)));

var binDir = HostingEnvironment.MapPath("~/bin");
var assemblyFilter = new AssemblyFilter(binDir);

container.Register(Types.FromAssemblyInDirectory(assemblyFilter)
     .BasedOn<IEntity>()
     .Unless(t => t.IsAbstract || t.IsInterface)
     .WithServiceAllInterfaces()
     .LifestyleTransient());

// This doesn't work!
var items = container.Resolve(typeof(IEnumerable<Definition<IEntity>>));

First, I think that you should improve your design a bit. I don't know the actual context, but I believe that your intent is the following:

public interface IEntity
{
}

public class Entity1 : IEntity
{
}

public class Entity2 : IEntity
{
}

public abstract class Definition<TEntity>
    where TEntity : IEntity
{
}

public class Entity1Definition : Definition<Entity1>
{
}

public class Entity2Definition : Definition<Entity2>
{
}

With this design you have the problem that the following code is not valid:

Definition<IEntity> definition = new Entity1Definition();

In order for this to work you should introduce a covariant generic interface for the IEntity type. More on covariance and contravariance you can find here: Covariance and Contravariance in Generics

So I suggest you introduce the following interface:

public interface IDefinition<out TEntity>
    where TEntity : IEntity
{
}

Note the out keyword that marks the interface as covariant. And then derive your Definition<TEntity> from this interface:

public abstract class Definition<TEntity> : IDefinition<TEntity>
    where TEntity : IEntity
{
}

Now, when we have set the design in such way the rest is easy. We can register the components like this:

WindsorContainer container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(
        new CollectionResolver(container.Kernel, true));

container.Register(Types.FromThisAssembly()
        .BasedOn(typeof(IDefinition<>))
        .Unless(t => t.IsAbstract || t.IsInterface)
        .WithServices(typeof(IDefinition<IEntity>))
        .LifestyleTransient());

And then resolve them:

var items = container.ResolveAll(typeof(IDefinition<IEntity>));

Note, that to resolve all instances for a registered service in Windsor you should invoke the ResolveAll method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM