Unity循环引用注释对象

时间:2015-01-14 05:02:04

标签: c# unity-container

我尝试使用Unity实现IoC的遗留应用程序(使用源代码)。 我目前面临的问题是,我有两个循环引用的类。

A类参考B类 B类参考A类

我通过使用带注释的属性设置器来注入每个依赖项;

On class A:
[Dependency]
public IServiceA ServiceA { get; set; }


On class B:
[Dependency]
public IServiceB ServiceB { get; set; }

Unity将因此而进入循环引用。 有没有办法绕过(除了重构里面的方法)因为这些类是遗留的,我不想花这么多精力去改变它们的设计?

3 个答案:

答案 0 :(得分:1)

当您尝试解决A时,Unity将执行此步骤。

Create A
Look at Properties for A and create them
Found B will create B
Look at Properties for B and create them
Found A will Create A

你陷入了困境。

您最好的选择是创建A和B所依赖的C.但是C不依赖于A或B.

答案 1 :(得分:0)

我同意重构是最佳做法,但您可以通过将一个或两个属性更改为Lazy<T>来实现您的目标。然后,在使用该属性之前,Unity将不会解析其他实例。

On class A:
[Dependency]
public Lazy<IServiceA> ServiceA { get; set; }


On class B:
[Dependency]
public Lazy<IServiceB> ServiceB { get; set; }

或者您可以更改其注册生命周期,以便重用相同的实例。如果您不希望共享相同的实例,这可能对您不起作用。也许PerResolveLifetime会起作用吗?

  1. 解析A(实例化A)
  2. 检测B依赖
  3. 解析B(实例B)
  4. 检测依赖
  5. 解决A(由于生命周期重用实例A并完成递归)
  6. 示例:

    container.RegisterType<A>(new PerResolveLifetimeManager());
    

答案 2 :(得分:0)

这确实是Unity令人沮丧的局限。但是,有一个2遍解决方案:

[TestClass]
public class UnityTests
{
    [TestMethod]
    public void Cure_For_UnityNotBeingVerySmartAtBindingCircularDependentProperties()
    {
        var container = new UnityContainer();

        container.RegisterType<ISharedResource, SharedResource>(new ContainerControlledLifetimeManager());

        container.RegisterType<ICycleA, CycleA>(new ContainerControlledLifetimeManager(), new InjectionProperty("SharedResource"));
        container.RegisterType<ICycleB, CycleB>(new ContainerControlledLifetimeManager(), new InjectionProperty("SharedResource"));

        var a = container.Resolve<ICycleA>();
        var b = container.Resolve<ICycleB>();

        container.RegisterType<ICycleA, CycleA>("buildup", new ContainerControlledLifetimeManager());
        container.RegisterType<ICycleB, CycleB>("buildup", new ContainerControlledLifetimeManager());

        container.BuildUp(a, "buildup");
        container.BuildUp(b, "buildup");

        Assert.IsInstanceOfType(a, typeof(CycleA));
        Assert.IsInstanceOfType(a.Dependency, typeof(CycleB));
        Assert.AreSame(a, a.Dependency.Dependency);
    }
}

internal interface ISharedResource { }

class SharedResource : ISharedResource { }

class CycleB : ICycleB
{
    [Dependency]public ISharedResource SharedResource { get; set; }
    [Dependency]public ICycleA Dependency { get; set; }
}

class CycleA : ICycleA
{
    [Dependency]public ISharedResource SharedResource { get; set; }
    [Dependency]public ICycleB Dependency { get; set; }
}
interface ICycleB
{
    [Dependency]ISharedResource SharedResource { get; set; }
    [Dependency]ICycleA Dependency { get; set; }
}
interface ICycleA
{
    [Dependency]ISharedResource SharedResource { get; set; }
    [Dependency]ICycleB Dependency { get; set; }
}

它利用了InjectionProperty重载,它告诉Unity只连接指定的依赖项。

如果您的类具有共享资源(例如,日志记录服务),请在第1次传递时注册此依赖项,最后的BuildUp传递将所有类连接在一起。

它需要在所有类上调用Resolve和BuildUp,有点尴尬,但可以很容易地使用UnityContainer扩展自动化。

这应该由Microsoft解决,因为它是一个相当标准的用例。