我尝试使用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将因此而进入循环引用。 有没有办法绕过(除了重构里面的方法)因为这些类是遗留的,我不想花这么多精力去改变它们的设计?
答案 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会起作用吗?
示例:
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解决,因为它是一个相当标准的用例。