通过温莎城堡解决父母/孩子的问题

发布于 2024-11-03 17:31:11 字数 1423 浏览 6 评论 0原文

我不确定调用这个父/子,但是在这里,我有一个类似的情况,如下所示:

namespace ConsoleApplication1
{
    using System.Diagnostics;
    using System.Linq;
    using Castle.MicroKernel.Registration;
    using Castle.MicroKernel.Resolvers.SpecializedResolvers;
    using Castle.Windsor;

    class Program
    {
        static void Main(string[] args)
        {
            var container = new WindsorContainer();

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

            container.Register(
                Component.For<Parent>().LifeStyle.Singleton,
                Component.For<IChild>().ImplementedBy<Child1>().LifeStyle.Singleton);

            var p = container.Resolve<Parent>();

            // Fails...
            Debug.Assert(p.Children.First().Parent == p, "Parent should be resolved");
        }
    }

    class Parent
    {
        public IChild[] Children { get; set; }
    }

    interface IChild
    {
        Parent Parent { get; set; }
    }

    class Child1 : IChild
    {
        public Parent Parent { get; set; }
    }
}

我已将 CollectionResolver 添加到容器中。 Parent 和 Child1(使用 IChild 服务)都在容器中注册为单例。每当我尝试解析 Parent 实例时,我都会填充 Children 数组,但该数组中的 Child1 实例的 Parent 为 null。我期望将 Child1 的 Parent 属性设置为我当时试图解析的 Parent 实例。我可以理解 Parent 尚未完全激活,但由于其 ctor 已运行,Windsor 还不能注入此属性吗?有什么方法可以完成这项工作,或者我应该手动运行一些代码来设置子对象的父对象(这远非理想)?

提前致谢!

I am not sure calling this parent/child but here you go, I have a similar case like this:

namespace ConsoleApplication1
{
    using System.Diagnostics;
    using System.Linq;
    using Castle.MicroKernel.Registration;
    using Castle.MicroKernel.Resolvers.SpecializedResolvers;
    using Castle.Windsor;

    class Program
    {
        static void Main(string[] args)
        {
            var container = new WindsorContainer();

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

            container.Register(
                Component.For<Parent>().LifeStyle.Singleton,
                Component.For<IChild>().ImplementedBy<Child1>().LifeStyle.Singleton);

            var p = container.Resolve<Parent>();

            // Fails...
            Debug.Assert(p.Children.First().Parent == p, "Parent should be resolved");
        }
    }

    class Parent
    {
        public IChild[] Children { get; set; }
    }

    interface IChild
    {
        Parent Parent { get; set; }
    }

    class Child1 : IChild
    {
        public Parent Parent { get; set; }
    }
}

I have CollectionResolver added to the container. Both Parent and Child1 (with IChild service) are registered as singletons in the container. Whenever I try to resolve the Parent instance, I got my Children array populated but the Child1 instance in that array has a Parent of null. What I am expecting is the Parent property of the Child1 to be set to the Parent instance I am trying to resolve at that moment. I can understand that Parent is not fully activated yet, but since its ctor is run, can't Windsor inject this property yet? Are there any way to make this work or should I manually run some code to set Parents of child objects (which is far from ideal)?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月野兔 2024-11-10 17:31:11

Windsor 不会让你创建循环依赖链。如果您更改子级和父级定义,以便它们使用构造函数注入而不是属性注入,如下所示:

class Parent
{
    public Parent(IChild[] children)
    {
        Children = children;
    }

    public IChild[] Children { get; private set; }
}

interface IChild
{
    Parent Parent { get; }
}

class Child1 : IChild
{
    public Child1(Parent parent)
    {
        Parent = parent;
    }

    public Parent Parent { get; private set; }
}

当您现在运行测试时,您将看到 Windsor 抱怨依赖循环:

测试“M:Mike.DIDemo.WindsorSpike.ParentChild”失败:循环已完成
尝试解决依赖关系时检测到。依赖图
导致循环的结果是:
- 类型 Mike.DIDemo.Parent 中 Void .ctor(Mike.DIDemo.IChild[]) 的参数依赖项“children”类型“Mike.DIDemo.IChild[]”
- 类型 Mike.DIDemo.Child1 + 参数中的 Void .ctor(Mike.DIDemo.Parent) 的服务依赖项“父”类型“Mike.DIDemo.Parent”
Void 的依赖项“children”类型“Mike.DIDemo.IChild[]”
Mike.DIDemo.Parent 中的 .ctor(Mike.DIDemo.IChild[])

当您有必需的依赖项时,使用构造函数注入总是更好。使用属性注入告诉 Windsor 该依赖项是可选的:如果可以,请提供组件,否则只需将属性保留为 null。在这种情况下,子级首先被解析,因此当创建父级依赖项时,Windsor 发现会产生循环并将其保留为空。

这里的解决方案是在解析子级时填充父级,方法是将一些代码放入父级构造函数中。

class Parent
{
    public Parent(IChild[] children)
    {
        Children = children;
        foreach (var child in children)
        {
            child.Parent = this;
        }
    }

    public IChild[] Children { get; private set; }
}

interface IChild
{
    Parent Parent { get; set;  }
}

class Child1 : IChild
{
    public Parent Parent { get; set; }
}

Windsor won't let you create a cyclic dependency chain. If you change your child and parent definitions so that they use constructor injection rather than property injection as follows:

class Parent
{
    public Parent(IChild[] children)
    {
        Children = children;
    }

    public IChild[] Children { get; private set; }
}

interface IChild
{
    Parent Parent { get; }
}

class Child1 : IChild
{
    public Child1(Parent parent)
    {
        Parent = parent;
    }

    public Parent Parent { get; private set; }
}

When you run your test now, you'll see that Windsor complains about a dependency cycle:

Test 'M:Mike.DIDemo.WindsorSpike.ParentChild' failed: A cycle was
detected when trying to resolve a dependency. The dependency graph
that resulted in a cycle is:
- Parameter dependency 'children' type 'Mike.DIDemo.IChild[]' for Void .ctor(Mike.DIDemo.IChild[]) in type Mike.DIDemo.Parent
- Service dependency 'parent' type 'Mike.DIDemo.Parent' for Void .ctor(Mike.DIDemo.Parent) in type Mike.DIDemo.Child1 + Parameter
dependency 'children' type 'Mike.DIDemo.IChild[]' for Void
.ctor(Mike.DIDemo.IChild[]) in Mike.DIDemo.Parent

It's always better to use constructor injection when you have a required dependency. Using property injection tells Windsor that the dependency is optional: Supply the component if you can, otherwise just leave the property null. In this case the children were resolved first, so when it came to create the Parent dependency Windsor saw that a cycle would result and left it null.

The solution here is to populate the Parent when the children are resolved, by putting some code in the Parent constructor.

class Parent
{
    public Parent(IChild[] children)
    {
        Children = children;
        foreach (var child in children)
        {
            child.Parent = this;
        }
    }

    public IChild[] Children { get; private set; }
}

interface IChild
{
    Parent Parent { get; set;  }
}

class Child1 : IChild
{
    public Parent Parent { get; set; }
}
思念满溢 2024-11-10 17:31:11

实际上,可以在不调用其构造函数的情况下创建对象。它的所有字段都将为空,但您将拥有对对象的引用。此功能在 Windsor 中未实现,需要此功能的东西可能是设计味道。

Actually it is possible to create an object without invoking its constructor. All of its fields will be null, but you'll have a reference to object. This feature is not implemented in Windsor, and something that requires this is likely to be a design smell.

黒涩兲箜 2024-11-10 17:31:11

这是一个更好一点的变体:)

container.Register(Component.For<SearchCommand>());
container.Register(Component.For<ShowOptionsCommand>());
container.Register(Component.For<MainWindowViewModel>().OnCreate(new Action<MainWindowViewModel>(p => p.SetUpCommands())));

public class MainWindowViewModel
{
    public ShowOptionsCommand ShowOptions { get; set; }
    public SearchCommand Search { get; set; }

    public MainWindowViewModel()
    {
    }

    public void SetUpCommands()
    {
        this.ShowOptions.Host = this;
        this.Search.Host = this;
    }
}

This is a variation that's a bit nicer :)

container.Register(Component.For<SearchCommand>());
container.Register(Component.For<ShowOptionsCommand>());
container.Register(Component.For<MainWindowViewModel>().OnCreate(new Action<MainWindowViewModel>(p => p.SetUpCommands())));

public class MainWindowViewModel
{
    public ShowOptionsCommand ShowOptions { get; set; }
    public SearchCommand Search { get; set; }

    public MainWindowViewModel()
    {
    }

    public void SetUpCommands()
    {
        this.ShowOptions.Host = this;
        this.Search.Host = this;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文