1

孩子我不知道调用这个父/子,但在这里,你走了,我也有类似的情况是这样的:解决家长/与温莎城堡

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属性设置为我正在尝试解决的父实例。我可以理解,父母尚未完全激活,但自从ctor运行后,Windsor无法注入此属性吗?有什么办法可以做到这一点吗?或者我应该手动运行一些代码来设置子对象的父母(这很不理想)?

在此先感谢!

回答

2

温莎不会让你创建一个循环依赖链。如果你改变你的孩子和家长的定义,以便他们使用构造函数注入,而不是财产注射如下:

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

现在当你运行你的测试,你会看到温莎抱怨依赖周期:

测试'M:Mike.DIDemo.WindsorSpike.ParentChild'失败:尝试解析依赖关系时检测到周期为 。导致循环的依赖关系图 是: - 类型为Mike.DIDemo.Parent的Void .ctor(Mike.DIDemo.IChild [])的参数相关性'children'类型'Mike.DIDemo.IChild []' - 服务依赖项'父'类型'Mike.DIDemo.Parent'为类型Mike.DIDemo.Child1中的void.ctor(Mike.DIDemo.Parent)+参数 依赖项'children'type'Mike.DIDemo.IChild []'for Void .ctor(Mike.DIDemo.IChild [])在Mike.DIDemo.Parent

它总是更好地使用构造器注入,当你有一个需要的依赖。使用属性注入告诉Windsor该依赖关系是可选的:如果可以,请提供组件,否则只需将该属性留空即可。在这种情况下,儿童首先得到了解决,因此,当创建父亲依赖关系时,温莎发现一个循环会导致并将其留空。

这里的解决方案是通过在Parent构造函数中放置一些代码来解决子代问题时填充Parent。

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; } 
} 
+0

很公平。尽管闻起来我会走这条路。 – huseyint 2011-04-27 11:59:11

+0

我真的不知道温莎是否是您手边工作的正确工具。看起来你正在创建一个域对象图。让Windsor创建域实例通常不是一个好主意,通常有一些存储库提供它们。然后你会问温莎的存储库,而不是域实例。 – 2011-04-27 13:02:29

+0

实际上,这里的Parent表示WPF屏幕的ViewModel,而Child表示可以在该屏幕上调用的Action,它们可视化为Button控件。我的ViewModel应该知道可用的动作来呈现它们,并且每个动作都应该知道它们正在与之交互的ViewModel。这似乎是使用依赖容器的好例子,因为我有一些内置的操作以及通过扩展提供的自定义操作。 – huseyint 2011-04-27 14:51:38

0

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

0

这是一个变化,这是一个有点更好:)

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