In the previous post I said there’s one more new feature in Windsor 3.2 related to open generic components.
Take the following class for example:
public class Foo<T, T2> : IFoo<T> { }
Notice it has arity of 2 (two generic parameters, T
and T2
) and the interface it implements has arity of 1.
If we have a generic component for this class what should be supplied for T2
when we want to use it as IFoo<Bar>
?
By default, if we just register the component and then try to use it we’ll be greeted with an exception like the following:
Requested type GenericsAndWindsor.IFoo`1[GenericsAndWindsor.Bar] has 1 generic parameter(s), whereas component implementation type GenericsAndWindsor.Foo`2[T,T2] requires 2.
This means that Windsor does not have enough information to properly create that component for you.
You can instruct Windsor which types it should use to close this generic component by supplying an implementation of IGenericImplementationMatchingStrategy.
Please consut the documentation for examples of how to do that.
Specifying implementation generic arguments: IGenericImplementationMatchingStrategy
The IGenericImplementationMatchingStrategy
interface allows you to plug in your own logic telling Windsor how to close the implementation type for a given requested service. The following trivial implementation simply uses string
for the other argument, therefore allowing the component to be successfully constructed.
public class UseStringGenericStrategy : IGenericImplementationMatchingStrategy { public Type[] GetGenericArguments(ComponentModel model, CreationContext context) { return new[] { context.RequestedType.GetGenericArguments().Single(), typeof (string) }; } }
The contract is quite simple, given a ComponentModel
and CreationContext
(which will tell you what the requested closed type is) you return the right types to use for generic arguments when closing the implementation type of the model
.
You hook it up in exactly the same way as IGenericServiceStrategy
(and yes, there’s an overload that allows you to specify both).
container.Register(Component.For(typeof (IFoo<>)) .ImplementedBy(typeof (Foo<,>), new UseStringGenericStrategy()) .LifestyleTransient());