Unity实例的access属性
本文关键字:属性 access 实例 Unity | 更新日期: 2023-09-27 18:05:30
我在构造器上实现了Unity注入。我有以下内容:
interface IA
{
DoSomething();
}
class A : IA
{
private List<MyType> List;
public A(List<MyType> list)
{
this.List = list;
}
DoSomething()
{
// do something with this.List
}
}
interface IB
{
List<MyType> GetList();
}
class B : IB
{
public List<MyType> GetList() { }
}
class C
{
private A MyA;
public C(IB b)
{
this.MyA = new A(b.GetList());
}
public DoSomethingInA()
{
this.MyA.DoSomething();
}
}
我想在类C的构造函数中删除"新A()",并使用IA注入,但我不知道如何注册类型IA的A,在构造函数中接收实例的属性,而不是实例本身。
我不能改变A的实现!!List<>应该在构造函数中接收。
C
类的构造函数做的太多了;注入器构造函数应该很简单。因此,在构建对象图时不调用GetList
,而是推迟到稍后的时刻,在A
和C
中都注入IB
,如下所示:
class A : IA
{
private IB b;
public A(IB b) {
this.b = b;
}
DoSomething() {
var list = this.b.GetList();
// do something with this.List
}
}
class C
{
private IB b;
public C(IB b) {
this.b = b;
}
}
这简化了您的注册,您的代码,并允许您自信地编写对象图。
如果类型不受您的控制,您应该考虑使用第三方类型。一般来说,您应该小心让容器自动连接这样的类型,因为维护该类型的人可能会向该类型添加新的构造函数,这可能会破坏您的DI注册(更多信息在这里)。
因此,与其让容器自动连接该类型,不如注册一个lambda表达式来创建该第三方类型的实例。例如:container.Register<IA>(new InjectionFactory(c => new A(c.Resolve<IB>().GetList())));
但是,请注意,在这种情况下,您仍然在构建对象图期间做了太多的事情,并且(取决于GetList
在幕后做了什么)可能会使验证图的正确性变得更加困难。
因此,由于您正在使用第三方类型,该类型在其构造过程中依赖于某些运行时类型,因此您可能需要考虑推迟该类型的创建。如果您为IA
创建代理类,您将能够延迟A
的创建,而无需应用程序了解它。这个代理可能看起来像这样:
class DelayedAProxy : IA
{
private readonly Lazy<IA> a;
public DelayedAProxy(Lazy<IA> a) {
this.a = a;
}
public DoSomething() {
this.a.Value.DoSomething();
}
}
你可以这样注册:
container.Register<IA>(new InjectionFactory(c =>
{
var lazy = new Lazy<IA>(() => new A(c.Resolve<IB>().GetList()));
new DelayedAProxy(lazy);
}));
这里我们没有直接注册A
,而是注册DelayedAProxy
,并且代理只会在DoSomething
第一次执行时创建A
,这将是在创建完整的对象图之后。
或者,您的代理也可以只依赖于IB
并在内部创建lazy。就像这样:
class DelayedAProxy : IA
{
private readonly Lazy<IA> a;
public DelayedAProxy(IB b) {
this.a = new Lazy<IA>(() => new A(b.GetList()));
}
public DoSomething() {
this.a.Value.DoSomething();
}
}
这样做的好处是DelayedAProxy
的注册变得更加容易:
container.RegisterType<IA, DelayedAProxy>();
虽然看起来在这种情况下DelayedAProxy
构造函数又做了很多事情,但实际上它只是用委托创建了Lazy。GetList
只在代理构建完成后调用。
我最终改变了设计,并使用方法注入依赖,而不是构造函数,如:
interface IA
{
Initialize(List<something> list);
DoSomething();
}
class C
{
private IA MyA;
public C(IB b, IA a)
{
this.MyA = a;
this.MyA.Initialize(b.GetList());
}
public DoSomethingInA()
{
this.MyA.DoSomething();
}
}
初始化在构造函数中完成,以减少对当前代码调用DoSomething()的影响,也可能是:
public DoSomethingInA()
{
this.MyA.DoSomething(b.GetList());
}
但是正如我所说,它对现有代码的影响更大