统一循环引用注释对象
本文关键字:注释 对象 引用 循环 | 更新日期: 2023-09-27 18:37:22
我正在尝试使用遗留应用程序(带有源代码)来使用 Unity 实现 IoC。我目前面临的问题是,我有 2 个相互循环引用的类。
A 类参考 B 类B 类参考 A 类
我通过使用带有注释的属性设置器注入每个依赖项;
On class A:
[Dependency]
public IServiceA ServiceA { get; set; }
On class B:
[Dependency]
public IServiceB ServiceB { get; set; }
因此,Unity 将进入循环引用。有没有办法绕过(除了重构里面的方法),因为这些类是遗留的,我不想花太多精力来改变它们的设计?
当您
尝试解析 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。
我同意重构是最佳实践,但是您可以通过更改要Lazy<T>
的一个或两个属性来实现您所追求的。 然后,Unity 不会解析另一个实例,直到您使用该属性。
On class A:
[Dependency]
public Lazy<IServiceA> ServiceA { get; set; }
On class B:
[Dependency]
public Lazy<IServiceB> ServiceB { get; set; }
或者,您可以更改其注册生存期,以便它们重复使用相同的实例。 如果您不希望共享相同的实例,这可能对您不起作用。 也许PerResolveLifetime会起作用?
- 解析 A(实例化 A)
- 检测 B 依赖关系
- 解析 B(实例化 B)
- 检测依赖关系
- 解析 A(由于生存期而重用实例 A,并完成递归)
例:
container.RegisterType<A>(new PerResolveLifetimeManager());
这确实是 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; }
}
它利用注入属性重载,该重载告诉 Unity 仅连接指定的依赖项。
如果您的类具有共享资源(例如日志记录服务),请在第一次传递时注册此依赖项,最后的 BuildUp 传递将所有类连接在一起。
它确实需要在所有类上调用 Resolve 和 BuildUp,有点尴尬,但可以使用 UnityContainer 扩展相当容易地实现自动化。
这应该由Microsoft解决,因为它是一个相当标准的用例。