Reputation: 9861
Assume that I have the following class structure:
public class Outer
{
[Dependency]
public Func<Inner> InnerFactory { get; set; }
}
public class Inner
{
}
In Autofac this can be done easily in the following way (and describes the behaviour I am looking for; ignore the fact that this is a stupid contrived example):
[TestMethod]
public void AutofacMakesThisEasy()
{
var builder = new ContainerBuilder();
builder.RegisterType<Outer>().PropertiesAutowired();
builder.RegisterType<Inner>().InstancePerOwned<Outer>();
var container = builder.Build();
var outer1 = container.Resolve<Owned<Outer>>().Value;
var inner1 = outer1.InnerFactory();
var inner2 = outer1.InnerFactory();
var outer2 = container.Resolve<Owned<Outer>>().Value;
var inner3 = outer2.InnerFactory();
var inner4 = outer2.InnerFactory();
Assert.AreNotSame(outer1, outer2, "outer1 == outer2");
Assert.AreSame(inner1, inner2, "inner1 != inner2");
Assert.AreNotSame(inner2, inner3, "inner2 == inner3");
Assert.AreSame(inner3, inner4, "inner3 != inner4");
}
How can I achieve the same behaviour in unity so the following test passes?
[TestMethod]
public void UnityHasMeScratchingMyHead()
{
var container = new UnityContainer();
//// What shoud I do here?
var outer1 = container.Resolve<Outer>();
var inner1 = outer1.InnerFactory();
var inner2 = outer1.InnerFactory();
var outer2 = container.Resolve<Outer>();
var inner3 = outer2.InnerFactory();
var inner4 = outer2.InnerFactory();
Assert.AreNotSame(outer1, outer2, "outer1 == outer2");
Assert.AreSame(inner1, inner2, "inner1 != inner2");
Assert.AreNotSame(inner2, inner3, "inner2 == inner3");
Assert.AreSame(inner3, inner4, "inner3 != inner4");
}
Note: I would dearly love to ditch Unity for a decent IoC, but that is going to be a very hard sell.
Upvotes: 3
Views: 1087
Reputation: 127553
If InnerFactory
was just Inner
instead of Func<Inner>
The solution would be PerResolveLifetimeManager
[TestMethod]
public void UnityHasMeScratchingMyHead()
{
var container = new UnityContainer();
container.RegisterType<Inner>(new PerResolveLifetimeManager());
var outer1 = container.Resolve<Outer>();
//... and so on.
However because you have a factory you need to make it a little more complicated. You need to make the factory PerResolve then have the objects the factory makes all the same instance (ContainerControlledLifetimeManager
). You do that via the following:
[TestMethod]
public void UnityHasMeScratchingMyHead()
{
var container = new UnityContainer();
container.RegisterType<Func<Inner>>(new PerResolveLifetimeManager(), new InjectionFactory(x =>
{
var child = x.CreateChildContainer();
child.RegisterType<Inner>(new ContainerControlledLifetimeManager());
return new Func<Inner>(() => child.Resolve<Inner>());
}));
var outer1 = container.Resolve<Outer>();
var inner1 = outer1.InnerFactory();
var inner2 = outer1.InnerFactory();
var outer2 = container.Resolve<Outer>();
var inner3 = outer2.InnerFactory();
var inner4 = outer2.InnerFactory();
Assert.AreNotSame(outer1, outer2, "outer1 == outer2");
Assert.AreSame(inner1, inner2, "inner1 != inner2");
Assert.AreNotSame(inner2, inner3, "inner2 == inner3");
Assert.AreSame(inner3, inner4, "inner3 != inner4");
}
One thing of note, Unity is easily extensible. If you are going to be doing this frequently with a little work you could make a InstancePerOwnedLifetimeManager<T>
and just use that and not need to worry about generating factories at all.
Upvotes: 3