我有一个实现两个接口的类:
interface IA { int X { get; } }
interface IB { int X { get; } }
class C : IA, IB
{
public C(int x) { X = x; }
public int X { get; }
}
然后,我将IA
和IB
映射到 Unity 容器中的C
,并检查是否使用了正确的注册:
var container = new UnityContainer();
container
.RegisterType<IA, C>(new InjectionConstructor(1))
.RegisterType<IB, C>(new InjectionConstructor(2));
var a = container.Resolve<IA>();
a.X.ShouldBe(1); // Actually it's 2
在这里,我得到a.X
等于 2 而不是 1。因此,使用第二个注册而不是第一个注册。
谁能解释,为什么上述注册会相互干扰?有什么理智的理由吗?
从(简化的)高级 Unity 存储两条在解析时使用的信息:
- 类型映射
- 建造计划
要记住的关键点是,类型映射和目标类型的构建是单独的离散步骤。
类型映射存储"发件人"类型和"收件人"类型之间的映射。 因此,在示例代码中IA
=>C
和IB
=>C
。
构建计划包含构造"to"目标类型所需的步骤。 在本例中,该类型为C
。
所以当
.RegisterType<IA, C>(new InjectionConstructor(1))
称为 从IA
到C
创建类型映射,并创建与目标类型关联的构建计划策略C
并将其保存在内存中。 构建计划策略将包括默认生存期管理器和值为 1 的InjectionConstructor
。
下一个何时
.RegisterType<IB, C>(new InjectionConstructor(2));
称为 从IB
到C
创建类型映射,并在内存中更新与目标类型C
关联的构建计划策略。 这会将构建计划策略更改为使用InjectionConstructor(2)
而不是InjectionConstructor(1)
。
现在定义了两个类型映射(IA
=C
和IB
=>C
),但仍然只有一个C
构建计划。 这就是 resolve 返回值 2 而不是 1 的原因。(您可以通过直接解析C
并检查 X:container.Resolve<C>()
的值来验证这一点)。
如果要为同一目标类型提供多个生成计划,则可以使用命名注册。例如,您可以使用 from 接口的名称(或您想要的任何其他字符串值,但接口的名称在这里似乎很合适)进行注册:
var container = new UnityContainer();
container
.RegisterType<IA, C>(typeof(IA).Name, new InjectionConstructor(1))
.RegisterType<IB, C>(typeof(IB).Name, new InjectionConstructor(2));
var a = container.Resolve<IA>(typeof(IA).Name);
a.X.ShouldBe(1); // will be 1