在一些城堡组件的运行时设置中苦苦挣扎

时间:2009-08-21 10:17:08

标签: c# .net inversion-of-control castle-windsor

我的问题(我认为)可以通过这个问题简单描述:

如何让“Manager”类获得已注册为注入其中的组件的特定接口的所有可能具体实现的列表,以便它可以迭代它们? (由于令人讨厌的架构原因,我无法使用app.config来注册我的组件 - 所以我只想运行时注册)

修改
啊哈! - 发现我可以使用以下内容传递我自己的配置文件:

var container = new WindsorContainer(new XmlInterpreter("filename"));

所以 - 我可以使用下面所述的xml配置路由 - 这意味着我不必担心子对象的实例化,因为它们已经在我的真实生活情境中注入了依赖项。

修改




为了尝试帮助你理解我的问题,我在下面列出了一个简单的复制品,表明我的困惑! (请原谅可怕的域名概念!)

这是一个简单的控制台应用程序,它有一个管理器,可以对给定的对象列表运行操作。

代码:

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

使用的配置文件如下所示:

  

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

我的问题:

以上一切正常。但是我不能在xml配置文件中定义我有哪种类型的噪音制作者。直到运行时我才会知道我是否有猫,狗,2只猫和金鱼等......

我能看到的唯一方法是通过以下代码进行描述。这个问题是我必须实例化我的NoiseMakers:“Dog”和“Cat”。对Castle来说这似乎是错误的,而在我的实际例子中,这是我真的不想做的事情。那么我做错了什么? 如何让“Manager”类获得已注册为注入其中的组件的特定接口的所有可能具体实现的列表,以便它可以迭代它们?

        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 个答案:

答案 0 :(得分:1)

最简单的方法是实现SubDependancyResolver来解析数组,然后在construtor中传入类型。

取自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>();
}

容器现在将所有动物类型注入AnimalManager类供您使用。

科林G

答案 1 :(得分:0)

如下所示,这允许我注册接口'IAnimal'的每个实现,然后使用'ResolveAll'将所有实现作为集合返回。

希望有所帮助

奥利

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