Reputation: 4408
I have a class which implements two interfaces:
interface IA { int X { get; } }
interface IB { int X { get; } }
class C : IA, IB
{
public C(int x) { X = x; }
public int X { get; }
}
Then I map IA
and IB
on C
in a Unity container and check that a correct registration is used:
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
Here I'm getting a.X
equals 2 instead of 1. Hence the second registration is used instead of the first one.
Who can explain, why above registrations interfer each other? Is there any sane reason for it?
Upvotes: 1
Views: 66
Reputation: 22655
From a (simplified) high level Unity stores two pieces of information that are used when resolving:
The key point to keep in mind is that type mapping and the building of the target type are separate discrete steps.
Type mapping stores the mapping between the "from" type and the "to" type. So, in the sample code IA
=>C
and IB
=>C
.
The build plan contains the steps required to construct the "to" target type. In this case that type is C
.
So when
.RegisterType<IA, C>(new InjectionConstructor(1))
is called a type mapping is created from IA
to C
and the build plan strategies associated with the target type C
are created and saved in memory. The build plan strategies would include the default lifetime manager and the InjectionConstructor
with a value of 1.
Next when
.RegisterType<IB, C>(new InjectionConstructor(2));
is called a type mapping is created from IB
to C
and the build plan strategies associated with the target type C
are updated in memory. This would change the build plan strategies to use the InjectionConstructor(2)
instead of InjectionConstructor(1)
.
Now there are two type mappings defined (IA
=C
and IB
=>C
) but still only one build plan for C
. That is why the resolve returns a value of 2 instead of 1. (You could verify this by resolving C
directly and checking the value of X: container.Resolve<C>()
).
If you want to have multiple build plans for the same target type then you could use named registrations. For example you could register using the name of the from interface (or any other string value you wanted but the name of the interface seems apropos here):
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
Upvotes: 1