Non-magic property injection in Unity

This article was originally published in my blog (affectionately referred to as blargh) on . The original blog no longer exists as I've migrated everything to this wiki.

The original URL of this post was at https://tmont.com/blargh/2010/12/non-magic-property-injection-in-unity. Hopefully that link redirects back to this page.

Unity provides a way to perform injection on properties, meaning that when an object is resolved through its DI container, it will inject values for pre-defined properties. For example:

C♯
public class Foo {
  public string Bar { get; set; }
}

// somewhere else...
container.RegisterType<Foo>(new InjectionProperty("Bar", "oh hai!"));

var foo = container.Resolve<Foo>();
Console.WriteLine(foo.Bar); // "oh hai!"

Pretty nifty, but it still reeks of .NET 2.0 non-lambda lameness. This sucks because you can't do all the cool stuff you're accustomed to, like type-safety, refactoring and static analysis.

So I fixed that. Unfortunately, Microsoft made the InjectionProperty class impressively difficult to extend, so we use the composite pattern to achieve greatness.

C♯
public class NonMagicInjectionProperty<T> : NonMagicInjectionProperty<T, object> {
	public NonMagicInjectionProperty(Expression<Func<T, object>> propertyAccessor) : base(propertyAccessor) { }
	public NonMagicInjectionProperty(Expression<Func<T, object>> propertyAccessor, object propertyValue) : base(propertyAccessor, propertyValue) { }
}

public class NonMagicInjectionProperty<T, TReturn> : InjectionMember {
	private const string ErrorMessage = "Expected lambda expression like: foo => foo.Bar, where Bar is the name of the property to be injected";
	private readonly InjectionProperty injectionProperty;

	public NonMagicInjectionProperty(Expression<Func<T, TReturn>> propertyAccessor) {
		injectionProperty = new InjectionProperty(GetPropertyNameFromExpression(propertyAccessor));
	}

	public NonMagicInjectionProperty(Expression<Func<T, TReturn>> propertyAccessor, TReturn propertyValue) {
		injectionProperty = new InjectionProperty(GetPropertyNameFromExpression(propertyAccessor), propertyValue);
	}

	private static string GetPropertyNameFromExpression(Expression<Func<T, TReturn>> expression) {
		var parameterName = expression.Parameters[0].Name;
		var memberExpression = expression.Body as MemberExpression;
		if (memberExpression == null) {
			throw new ArgumentException(ErrorMessage);
		}

		var leftSide = memberExpression.Expression as ParameterExpression;
		if (leftSide == null || leftSide.Name != parameterName) {
			throw new ArgumentException(ErrorMessage);
		}

		return memberExpression.Member.Name;
	}

	public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies) {
		injectionProperty.AddPolicies(serviceType, implementationType, name, policies);
	}
}

Now you can do stuff like this:

C♯
public class Foo {
  public string Bar { get; set; }
}

// somewhere else...
container.RegisterType<Foo>(new NonMagicInjectionProperty<Foo>(foo => foo.Bar, "oh hai!"));
// or for more type safety (but not super necessary, in my opinion)
container.RegisterType<Foo>(new NonMagicInjectionProperty<Foo, string>(foo => foo.Bar, "oh hai!"));

var foo = container.Resolve<Foo>();
Console.WriteLine(foo.Bar); // "oh hai!"

It's a little more verbose, but much more awesome.