Unity 2.0 – Automatic Builders
Contents
- Automatic Factories
- Property Injection
- Container.BuildUp
- Introducing “Automatic Builders”
- Creating “Automatic Builders”
Automatic Factories
I’ve been working with Unity 2.0 on a couple of projects recently (the source is at https://unity.codeplex.com – the microsoft.com download page should be up shortly although Unity is available as part of Enterprise Library 5.0). One of the new Unity features that I really like is the automatic factory support.
Suppose you have a common scenario where you have a class Foo that depends on SomeType:
class Foo
{
private SomeType _someType;
public Foo(SomeType someType)
{
_someType = someType;
}
public void DoSomething()
{
// use the instance
_someType.Blah();
}
}
Providing the container can resolve SomeType then you can happily call container.Resolve<Foo>. But what if SomeType is expensive to construct and you don’t always need it, or you need multiple instances? One approach is to take the container itself as a dependency and then call Resolve<SomeType> if/when you need an instance. This is generally regarded as an anti-pattern as you are tying yourself to the container and making it harder to see what dependencies your class has.
A better approach is to create a factory and then take the factory as a dependency.
class Foo
{
private readonly ISomeTypeFactory _someTypeFactory;
public Foo(ISomeTypeFactory someTypeFactory)
{
_someTypeFactory = someTypeFactory;
}
public void DoSomething()
{
// create instance if needed...
SomeType someType = _someTypeFactory.CreateSomeType();
someType.Blah();
}
}
This keeps the dependencies clearer, but requires you to create and register the SomeTypeFactory class. Unity 2.0 introduces automatic factories which let you do the following:
class Foo
{
private readonly Func<SomeType> _someTypeFactory;
public Foo(Func<SomeType> someTypeFactory)
{
_someTypeFactory = someTypeFactory;
}
public void DoSomething()
{
// create instance if needed...
SomeType someType = _someTypeFactory();
someType.Blah();
}
}
This has the benefits of the previous approach, but you don’t need to register Func<SomeType> with the container. Providing it can resolve SomeType then when it sees a dependency of Func<SomeType> it will automatically generate a lightweight factory that calls back to the container to resolve the type.
Property Injection
In the examples so far we have been focusing on constructor injection, but Unity also supports property and method injection. For example, suppose that SomeType had a dependency on an ILogger:
class SomeType
{
public ILogger Logger { get; set; }
public void Blah()
{
Logger.Log("In Blah");
}
}
We could configure Unity to use property injection so that calling Container.Resolve<SomeType>() would return us an instance of SomeType with the Logger property assigned to.
Container.BuildUp
Up to this point, we have been using Container.Resolve() to ask the container to provide us an instance. What if we already have an instance but need to configure it? Clearly constructor injection isn’t an option, but fortunately Unity provides the Container.BuildUp method to allow you to use property (& method) injection for just this purpose. So, with the SomeType definition above, we could configure Unity so that calling container.BuildUp(someType) would configure our existing instance of SomeType by assigning to the Logger property just as for the Resolve call.
Whilst the BuildUp method is useful, it does require that you have a reference to the container:
class Foo
{
private readonly IUnityContainer _container;
public Foo(IUnityContainer container)
{
_container = container;
}
public void DoSomething()
{
// use an instance of SomeType that someone else created...
_container.BuildUp(someType);
someType.Blah();
}
}
We’ve already seen that it isn’t necessarily desirable to take the container as a dependency. We could solve this using a similar approach to factories:
interface ISomeTypeConfigurer
{
void Configure(SomeType someType);
}
class SomeTypeConfigurer : ISomeTypeConfigurer
{
private readonly IUnityContainer _container;
public SomeTypeConfigurer(IUnityContainer container)
{
_container = container;
}
public void Configure(SomeType someType)
{
_container.BuildUp(someType);
}
}
And then use this from Foo:
class Foo
{
private readonly ISomeTypeConfigurer _configurer;
public Foo(ISomeTypeConfigurer configurer)
{
_configurer = configurer;
}
public void DoSomething()
{
// use an instance of SomeType that someone else created...
_configurer.Configure(someType);
someType.Blah();
}
}
This does allow us to remove the container dependency from Foo, but we’re back to creating configuration/factory classes to achieve this.
Introducing “Automatic Builders”
In the same way that Unity 2.0 adds support for automatic factories (i.e. automatically resolving Func<T> if it can resolve T), wouldn’t it be nice if it could also resolve an Action<T> to give you BuildUp support? This would let us write Foo as
class Foo
{
private readonly Action<SomeType> _someTypeBuilder;
public Foo(Action<SomeType> someTypeBuilder)
{
_someTypeBuilder = someTypeBuilder;
}
public void DoSomething()
{
// use an instance of SomeType that someone else created...
_someTypeBuilder(someType);
someType.Blah();
}
}
Full of hope, I tried this … and it didn’t work. Undeterred, I created a Unity Extension that adds this support
Creating “Automatic Builders”
Looking at the source code for Unity, the Func<T> support is provided in a class called DeferredResolveBuildPlanPolicy and uses an internal ResolveTrampoline class to perform the container.Resolve call. Being the original kind of guy that I am I created a DeferredBuildUpBuildPlanPolicy that uses a BuildUpTrampoline to perform the container.BuildUp call!
class DeferredBuildUpBuildPlanPolicy : IBuildPlanPolicy
{
public void BuildUp(IBuilderContext context)
{
if (context.Existing == null)
{
var currentContainer =
context.NewBuildUp<IUnityContainer>();
Type typeToBuild = GetTypeToBuild(
context.BuildKey.Type);
string nameToBuild = context.BuildKey.Name;
Delegate buildMethod = CreateBuilder(currentContainer,
typeToBuild, nameToBuild);
context.Existing = buildMethod;
DynamicMethodConstructorStrategy
.SetPerBuildSingleton(context);
}
}
private static Type GetTypeToBuild(Type t)
{
return t.GetGenericArguments()[0];
}
private static Delegate CreateBuilder(IUnityContainer
currentContainer, Type typeToBuild, string nameToBuild)
{
Type trampolineType = typeof(BuildUpTrampoline<>)
.MakeGenericType(typeToBuild);
Type delegateType = typeof(Action<>)
.MakeGenericType(typeToBuild);
MethodInfo buildMethod = trampolineType
.GetMethod("BuildUp");
object trampoline = Activator.CreateInstance(
trampolineType, currentContainer, nameToBuild);
return Delegate.CreateDelegate(delegateType, trampoline,
buildMethod);
}
private class BuildUpTrampoline<TItem>
{
private readonly IUnityContainer _container;
private readonly string _name;
public BuildUpTrampoline(IUnityContainer container,
string name)
{
this._container = container;
this._name = name;
}
public void BuildUp(TItem item)
{
_container.BuildUp<TItem>(item, _name);
}
}
}
With that class in place we need a way to tell Unity to use it so I created DeferredBuildUpExtension:
public class DeferredBuildUpExtension : UnityContainerExtension
{
protected override void Initialize()
{
Context.Policies.Set<IBuildPlanPolicy>(
new DeferredBuildUpBuildPlanPolicy(), typeof(Action<>));
}
}
This registers the DeferredBuildUpBuildPlanPolicy class for the Action<> type. To use this, just call Container.AddNewExtension<DeferredBuildUpExtension>() to get the “automatic builder” support that we showed in Introducing “Automatic Builders”. Basically, an “automatic builder” is to Container.BuildUp what an automatic factory is to Container.Resolve.
Wrap-up
Automatic factories are cool. But sometimes you have an instance that you didn’t create: maybe you’re working with an existing framework that created the object, or the object has been deserialised (e.g. from session state). In these instances “automatic builders” might just come in handy!
Originally posted by Stuart Leeks on April 28th 2010 here https://blogs.msdn.com/stuartleeks/archive/2010/04/28/unity-2-0-automatic-builders.aspx