Castle.Windsor:有条件地解决其他实现

时间:2011-12-13 20:01:06

标签: castle-windsor

我的域名看起来像这样:

public interface IParent{ IChild[] Children { get; set; } }

public class Parent1 : IParent
{
    public IChild[] Children { get; set; }
    public Parent1(IChild[] children) { Children = children; }
}

public class Parent2 : IParent
{
    public IChild[] Children { get; set; }
    public Parent2(IChild[] children) { Children = children; }
}

public interface IChild{}
public class Child1 : IChild{}
public class Child2 : IChild{}

我使用ArrayResolver为父母解决了多个孩子。 我需要的是,当我解决Parent1时,我只获得Child1实现(可能还有一些总是存在的) 但是当我解决Parent2时,我想添加Child2

我的第一次尝试是:

[TestFixture]
public class BasicUnderstandingTests
{
    [Test]
    public void CanAddImplementationInOverride()
    {
        var container = new WindsorContainer();

        container.Kernel.Resolver
                 .AddSubResolver(new ArrayResolver(container.Kernel));

        container.Register(Component
            .For<IParent>().ImplementedBy<Parent1>());
        container.Register(Component
            .For<IParent>().ImplementedBy<Parent2>().Named("Parent2")
            .ServiceOverrides(ServiceOverride.ForKey<IChild>().Eq<Child2>()));

        container.Register(Component
            .For<IChild>().ImplementedBy<Child1>());
        container.Register(Component
            .For<IChild>().ImplementedBy<Child2>());


        var p1 = container.Resolve<IParent>();
        Assert.IsAssignableFrom<Parent1>(p1);
        Assert.AreEqual(1, p1.Children.Length);

        var p2 = container.Resolve<IParent>("Parent2");
        Assert.IsAssignableFrom<Parent2>(p2);
        Assert.AreEqual(2, p2.Children.Length);
    }
}

但如果两个实现IChild都被注册,则第一个断言失败,如果只注册了第一个实现,则第二个断言失败。

有没有一种优雅的方式可以做到这一点我错过了?

1 个答案:

答案 0 :(得分:1)

好的,这是一个主要黑客,但这是一个有趣的小项目。我创建了一个自定义ISubDependencyResolver来处理这种情况(种类)。试试这个:而不是ArrayResolver:

public class ParentChildResolver : ISubDependencyResolver
{
    private readonly IKernel kernel;

    public ParentChildResolver(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
    {
        var number = model.Name.Substring(model.Name.Length - 1, 1);
        var childType = Type.GetType(String.Format("{0}.Child{1}", model.Service.Namespace, number));
        var children = kernel.ResolveAll<IChild>().Where(c => childType.IsAssignableFrom(c.GetType())).ToArray();
        return children;
    }

    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
    {
        return typeof (IChild[]).IsAssignableFrom(dependency.TargetType);
    }
}

它有一些主要的假设,使它真的很hacky:

  1. 它仅适用于名为“Parent1”到“Parent9”的类型(因此它只匹配“Child1”到“Child9”)。
  2. 它假设Child实现与Parent实现位于同一名称空间(可能对您不起作用)。
  3. 没有错误检查!
  4. 你也可以摆脱服务覆盖,因为它没有做任何事情。

    由于内核将所有子节点视为IChild对象,因此我无法想到更简单的方法。您需要查看这些IChild对象是否由父类的特定类型实现 - 我将这些对象与数字后缀相匹配。

    像我说的那样 - 主要的黑客。 :)