On Castle Windsor and open generic components

While Windsor supported open generics components since pretty much forever, there’s been some improvements in version 3.2 that I haven’t blogged about yet, but which can be pretty useful in some advanced scenarios. I’ll cover them in this and future blogpost.

Just so we’re clear – what are open generic components?

So what are open generic components? Components based on a generic type where we don’t specify the generic arguments. Like the following:

// register
container.Register(Component.For(typeof (IFoo<>))
	.ImplementedBy(typeof (Foo<>))
	.LifestyleTransient());

// will provide IFoo<Bar>, IFoo<Baz>, IFoo<any_valid_type>

In this case we say that the component provides IFoo<> closed over Bar, Baz etc

Being picky about what we’re closing over: IGenericServiceStrategy

Sometimes we want to restrict the types we want our components to support. C# language allows us to use generic constraints to specify that, and Windsor will obviously respect that, but sometimes we need to go beyond what language provides.

One realistic example might be restricting to specific types from a given assembly, like in this StackOverflow question.

Windsor 3.2 has a new hook point for just that – IGenericServiceStrategy, which allows you to plug custom logic to specify whether you want a component to support a given closed version of its open generic service.

Here’s a sample implementation limiting to types from a single assembly:

public class OnlyFromAssemblyStrategy : IGenericServiceStrategy
{
	private readonly Assembly assembly;

	public OnlyFromAssemblyStrategy(Assembly assembly)
	{
		this.assembly = assembly;
	}

	public bool Supports(Type service, ComponentModel component)
	{
		return service.GetGenericArguments().Single().Assembly == assembly;
	}
}

To hook the strategy:

container.Register(Component.For(typeof (IFoo<>))
	.ImplementedBy(typeof (Foo<>), new OnlyFromAssemblyStrategy(someAsembly))
	.LifestyleTransient());

Now when you need IFoo<SomeTypeFromWrongAssembly> either another component will need to supply it, or the dependency will not be satisfied (which, if the dependency is not optional, will result in exception).
Component Not Found exception