Imagine I have the following classes and interfaces:
public interface IService { }
public class DefaultService : IService { }
public
I figured out how to do this after a couple of hours messing around with NInject Convention's GenericBindingGenerator.
If anyone is interested I can post it.
Update:
///
/// Creates bindings on open generic types.
/// This is similar to the out-of-the-box , but allows a default class to be
/// specified if no other bindings can be found. See the test case for usages.
///
public class GenericBindingGeneratorWithDefault : IBindingGenerator
{
private static readonly Type TYPE_OF_OBJECT = typeof (object);
private readonly Type _contractType;
private Dictionary _cachedBindings = new Dictionary();
private readonly Type _defaultType;
public GenericBindingGeneratorWithDefault(Type contractType, Type defaultType)
{
if ( !( contractType.IsGenericType || contractType.ContainsGenericParameters ) )
{
throw new ArgumentException( "The contract must be an open generic type.", "contractType" );
}
_contractType = contractType;
_defaultType = defaultType;
}
///
/// Processes the specified type creating kernel bindings.
///
/// The type to process.
/// the scope callback.
/// The kernel to configure.
public void Process( Type type, Func scopeCallback, IKernel kernel )
{
if (type == _defaultType)
{
kernel.Bind(_contractType).ToMethod(
ctx =>
{
var requestedType = ctx.Request.Service;
var resolution = _cachedBindings.ContainsKey(requestedType)
? _cachedBindings[requestedType]
: _defaultType.MakeGenericType(ctx.GenericArguments);
return ctx.Kernel.Get(resolution);
});
}
else
{
Type interfaceType = ResolveClosingInterface(type);
if (interfaceType != null)
{
_cachedBindings[interfaceType] = type;
}
}
}
///
/// Resolves the closing interface.
///
/// Type of the target.
///
public Type ResolveClosingInterface( Type targetType )
{
if ( targetType.IsInterface || targetType.IsAbstract )
{
return null;
}
do
{
Type[] interfaces = targetType.GetInterfaces();
foreach ( Type @interface in interfaces )
{
if ( !@interface.IsGenericType )
{
continue;
}
if ( @interface.GetGenericTypeDefinition() == _contractType )
{
return @interface;
}
}
targetType = targetType.BaseType;
} while ( targetType != TYPE_OF_OBJECT );
return null;
}
}