使用Unity容器注册递归结构

5

能否将以下递归结构注册到Unity容器中:

public interface IFoo
{
    IBar[] Bars { get; set; }
}

public interface IBar
{
    IFoo[] Foos { get; set; }
}

假设每个接口都存在多个命名实例:
public class Foo1 : IFoo 
{
    public IBar[] Bars { get; set; }
}

public class Foo2 : IFoo
{
    public IBar[] Bars { get; set; }
}

public class Bar1 : IBar
{
    public IFoo[] Foos { get; set; }
}

public class Bar2 : IBar
{
    public IFoo[] Foos { get; set; }
}

而且还有注册:

var container = new UnityContainer();

container.RegisterType<IFoo, Foo1>("foo1");
container.RegisterType<IFoo, Foo2>("foo2");
container.RegisterType<IBar, Bar1>("bar1");
container.RegisterType<IBar, Bar2>("bar2");

var instanceOfBar = container.Resolve<IBar>("bar1");

如何配置Unity容器,使集合属性自动注入?

你的属性上没有看到任何 DependencyAttribute,这是有意为之吗? - Wiktor Zychla
你如何设想集合被初始化? - podiluska
2个回答

6

有一种方法可以将属性注释为依赖项。但在您的情况下,由于分辨率过程的无限性,这将不起作用。简单地说,您将得到堆栈溢出异常。为了实现这样的结构,我使用懒惰模式,因此只有在需要时才解析这样的集合:

 Func<IFoo[]> resolver;
 IFoo[] value;
 public IFoo[] Foos { get{
      if(value == null) value = resolver();
         return value;
     } 
 }

要使容器能够解析 Func<IFoo[]>,请添加以下内容:

 container.RegisterInstance<Func<IFoo[]>>(e => e.Resolve<IFoo[]>());

数组或元素的解析已经由Unity预先处理,它简单地映射到ResolveAll

然后只需通过构造函数注入Func<IFoo[]>即可。


但是,一旦您尝试解析所有的Foo对象,您将需要解析每个Foo对象的Bar属性,这将引发循环依赖项。惰性加载只是推迟了这个问题,而没有解决它。 - Faster Solutions
@更快的解决方案 这个想法是在某个时候你根本不会访问该属性。这样你就会打破这种循环依赖关系。否则,无论你是否使用Unity,这种结构都是毫无意义的。 - Rafal
我听到你了。我的担忧是,这基本上就像一场等待发生的意外。它确实打破了循环依赖关系,但是它很脆弱。实际上,为了使这种方法以稳健的方式运行,类的数据结构需要改变。 - Faster Solutions
我同意这个结构有缺陷,但问题很抽象且非常具体,所以我已经回答了这个问题。通过修改,强制Unity仅创建一次IFoo和IBar的实例,这是一个非常有用的解决方案。 - Rafal
我认为我们在灰色区域上存在分歧。我们都认为这个结构不适用于Unity。我们回答的主要区别在于,我说修复根本问题否则它将无法工作,而你说这里有一个解决方法,但其中包含风险。我的偏好始终是修复根本问题,因为最终它必然会反噬你。 - Faster Solutions
我意识到底层数据结构需要改变。问题在于目前不可能进行更改(这一点我在问题中应该提到),因此我采用了这种解决方法。Faster Solutions的答案也很有帮助,因为它确认了我最初的想法。感谢你们两个。 - Darin Dimitrov

3
你的问题的简单答案是否定的。如果通过解析Foo,你实例化了一个或多个Bar对象,而这些对象又实例化了一些Foo对象,则Unity将认为这是循环引用。
循环引用是Unity中的一个问题:Circular References

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接