检测Unity中循环依赖的原因

时间:2013-03-19 11:03:42

标签: inversion-of-control castle-windsor unity-container circular-dependency

是否可以将Unity配置为检测循环引用或拦截类型解析器以显示某些调试信息?

实施例

以下是一些依赖于彼此的接口和类

public interface IThing1 { }

public class Thing1 : IThing1
{
    private IThing2 _thing2;

    public Thing1(IThing2 thing2)
    {
        _thing2 = thing2;
    }

}

public interface IThing2 { }

public class Thing2 : IThing2
{
    private IThing1 _thing1;

    public Thing2(IThing1 thing1)
    {
        _thing1 = thing1;
    }
}

温莎城堡

如果在Castle Windsor中配置了这两种类型,它将抛出异常并提供一些调试信息以查找循环引用:

Castle.MicroKernel.CircularDependencyException: Dependency cycle has been detected when trying to resolve component 'CircularIoC.Thing1'.
The resolution tree that resulted in the cycle is the following:
Component 'CircularIoC.Thing1' resolved as dependency of
    component 'CircularIoC.Thing2' resolved as dependency of
    component 'CircularIoC.Thing1' which is the root component being resolved.

统一

如果Unity配置为解决这些类型

    private static void ResolveWithUnity()
    {
        var container = new UnityContainer();

        container.RegisterType<IThing1, Thing1>();
        container.RegisterType<IThing2, Thing2>();

        var thing = container.Resolve<IThing1>();

        container.Dispose();
    }

对container.Resolve&lt;&gt;的调用将导致StackOverflowException。

这是documented behaviour但是有一些更有用的信息会很好。是否有任何自定义可以提供有关循环引用的更多信息?

或者有没有办法挂钩到类型解析器进程来发出一些调试信息?我正在考虑装饰主类型解析器以输出正在解析的类型的名称。这将提供一些反馈和指向依赖项的指针,该指针导致循环引用。

虽然我知道改用不同的IoC可以解决问题,但不幸的是这不是一个选择。

1 个答案:

答案 0 :(得分:1)

Unity遗憾地不支持这个(非常重要的)功能。 如果你愿意放弃它,你可以使用一些弯头油脂来实现智能装饰。

您需要的是覆盖所有注册方法,并为依赖项(dependency graph)构建和更新数据结构。 然后编写一个预先形成DFS以检测循环依赖关系的方法,您可以将其用作注册过程的终结器,如果可能存在循环依赖关系则将检测预解析,或者根据特定的解析使用它请求类型。

正如你所看到的,它有很多工作......

另一种选择,就是用装饰器包装解析方法并捕获 StackOverflowException ,分析它以确保它是由解析过程产生的,并构建一个适当的循环依赖异常。 / p>