Fighting the installation of some components of the lock
My question (I think) can be simply described by this question:
How can I get the Manager class to have a list of all possible concrete implementations of a particular interface that have been registered as components injected into it so that it can traverse through them? (And due to annoying architecture reasons, I can't use app.config to register my components - so registration at runtime is just my guess)
EDIT:
Oh yes! - Found that I can pass to my own config file using something like:
var container = new WindsorContainer(new XmlInterpreter("filename"));
so I can just use the xml config route I talked about below - this means I don't have to worry about creating descendant objects as they themselves injected the dependencies themselves in my Real Life situation.
EDIT:
To try and help your understanding of my problem, I have provided a simple example below to demonstrate my confusion! (Please excuse the dreaded domain concept!)
This is a simple console application that has a manager that will trigger an action on the list of objects it has given.
Code:
public class Program {
public static void Main() {
var container = new WindsorContainer(new XmlInterpreter());
var manager = container.Resolve<AnimalManager>();
manager.PokeAnimals();
container.Release(manager);
}
}
public interface IMakeNoise {
void MakeNoise();
}
public class Cat : IMakeNoise {
public void MakeNoise() {
Console.WriteLine("Meow");
}
}
public class Dog : IMakeNoise {
public void MakeNoise() {
Console.WriteLine("Woof");
}
}
public class AnimalManager {
private readonly IList<IMakeNoise> noisemakers = new List<IMakeNoise>();
public AnimalManager(IList<IMakeNoise> noisemakers) {
this.noisemakers = noisemakers;
}
public void PokeAnimals() {
foreach (var noisemaker in noisemakers) {
noisemaker.MakeNoise();
}
}
}
The config file used looks like this:
<configSections>
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
</configSections>
<castle>
<components>
<component id="Dog" service="CastleListTest.IMakeNoise, CastleListTest"
type="CastleListTest.Dog, CastleListTest" />
<component id="Cat" service="CastleListTest.IMakeNoise, CastleListTest"
type="CastleListTest.Cat, CastleListTest" />
<component id="AnimalManager" service="CastleListTest.AnimalManager, CastleListTest"
type="CastleListTest.AnimalManager, CastleListTest">
<parameters>
<noisemakers>
<list>
<item>${Cat}</item>
<item>${Dog}</item>
</list>
</noisemakers>
</parameters>
</component>
</components>
</castle>
My problem:
Everything above works fine. However, I cannot determine in the xml config file what noisemakers I have. I won't know until runtime if I have a cat, dog, 2 cats and a goldfish or something else ...
The only way I can do this is best described in the code below. The problem is that I need to create an instance of my NoiseMakers: "Dog" and "Cat". This seems to be wrong, against a lock, and in my actual example, this is something I really don't want to do. So what am I doing wrong? How can I get the Manager class to have a list of all possible concrete implementations of a particular interface that has been registered as nested components so that it can iterate over them?
var container = new WindsorContainer();
container.AddComponent("Dog", typeof(IMakeNoise), typeof(Dog));
container.AddComponent("Cat", typeof(IMakeNoise), typeof(Cat));
container.AddComponent(
"AnimalManager", typeof(AnimalManager), typeof(AnimalManager)
);
IList<IMakeNoise> noisemakers = new List<IMakeNoise> {new Dog(), new Cat()};
var manager = container.Resolve<AnimalManager>(
new Hashtable { { "noisemakers", noisemakers } }
);
manager.PokeAnimals();
container.Release(manager);
source to share
The simplest thing is to implement SubDependancyResolver to resolve arrays and then pass the type in the constructor.
taken from hammett blog
public class ArrayResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public ArrayResolver(IKernel kernel)
{
this.kernel = kernel;
}
public object Resolve(CreationContext context, ISubDependencyResolver parentResolver,
ComponentModel model,
DependencyModel dependency)
{
return kernel.ResolveAll(dependency.TargetType.GetElementType(), null);
}
public bool CanResolve(CreationContext context, ISubDependencyResolver parentResolver,
ComponentModel model,
DependencyModel dependency)
{
return dependency.TargetType != null &&
dependency.TargetType.IsArray &&
dependency.TargetType.GetElementType().IsInterface;
}
}
public class AnimalManager
{
private readonly IAnimal[] _animals;
public AnimalManager(IAnimal[] animals)
{
_animals = animals
}
}
//Setup container somewhere
public IWindsorContainer ConfigureContainer()
{
IWindsorContainer container = new WindsorContainer().Register(AllTypes.FromAssemblyContaining<Cat>());
container.Kernel.Resolver.AddSubResolver(typeof(ArrayResolver));
IAnimalManager manager = container.Resolve<AnimalManager>();
}
The container will now inject all animal types into the AnimalManager class for use.
Colin g
source to share
Something like the following, this allows me to register each implementation of the "IAnimal" interface and then use "ResolveAll" to return all implementations as a collection.
Hope it helps
Ollie
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.Register(AllTypes.Pick().FromAssembly(Assembly.GetExecutingAssembly()).AllowMultipleMatches());
var dog = container.Resolve<Dog>();
var animals = container.ResolveAll<IAnimal>();
}
}
public interface IAnimal
{
}
public class Dog : IAnimal
{
}
public class Cat : IAnimal
{
}
public class Fish : IAnimal
{
}
source to share