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);

      

+2


source to share


2 answers


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

+1


source


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
{
}

      

0


source







All Articles