Search code examples
c#genericscastle-windsorwindsor-facilities

Register/Resolve partially closed generic descendant using open generic ancestor type with Castle Windsor


With ancestor class:

abstract class MyOpenGenericAncestor<T, TOptions>

and descendant class:

class MyPartiallyClosedDescendant<T> : MyOpenGenericAncestor<T, MyConcreteOptionsType>

I want to be able to resolve MyPartiallyClosedDescendant using MyOpenGenericAncestor, such as:

MyOpenGenericAncestor<T, TOptions> ResolveGeneric<T, TOptions>(TOptions options)
{
    // assume options are used for stuff
    return _container.Resolve<MyOpenGenericAncestor<T, TOptions>();
}

Is there a way to accomplish this? In this code's current implementation, the registration looks like:

var assemblyFilter = new AssemblyFilter("C:\\thePath\", "MyStuff.*.dll");
var myTypes = Classes
    .FromAssemblyInDirectory(assemblyFilter)
    .BasedOn(typeof(MyOpenGenericAncestor<,>))
    .WithServiceBase()
    .LifestyleTransient();

container.Register(myTypes);

With this registration, the MyPartiallyClosedDescendant is registered as a component, but calling ResolveGeneric(myConcreateOptionsInstance) causes a Castle.MicroKernel.ComponentNotFoundException with the message that no component for supporting the service MyOpenGenericAncestor`2[MyConcreateTType, MyConcreateOptionsType] was found. Getting that exception makes sense, but is there a way to register and/or resolve the descendant by requesting the ancestor?


Solution

  • In Castle, there is IGenericImplementationMatchingStrategy for this purpose. Unfortunately I'm not sure how to use it with convention registration, so at least this...

    public class MyOpenGenericAncestorMatchingStrategy : IGenericImplementationMatchingStrategy
    {
        public Type[] GetGenericArguments(ComponentModel model, CreationContext context)
        {
            return new[] { context.GenericArguments[1] };
        }
    }
    
    container.Register(Component.For(typeof(MyOpenGenericAncestor<,>))
    .ImplementedBy(typeof(MyPartiallyClosedDescendant<>), new MyOpenGenericAncestorMatchingStrategy()));