Imagine I have the following classes and interfaces:
public interface IService { }
public class DefaultService : IService { }
public
I took the liberty of refactoring the answer from @cbp, so that it works for the new IBindingGenerator signature in Ninject v3 conventions. It's pretty much replacing the Process()
method signature with the CreateBindings()
method signature, but I didn't test this, so there's a chance you'll have to tweak it a bit if you use it.
///
/// 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 TypeOfObject = typeof(object);
private readonly Type _contractType;
private readonly Dictionary _cachedBindings;
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");
_cachedBindings = new Dictionary();
_contractType = contractType;
_defaultType = defaultType;
}
///
/// Creates the bindings for a type.
///
/// The type for which the bindings are created.
/// The binding root that is used to create the bindings.
///
/// The syntaxes for the created bindings to configure more options.
///
public IEnumerable> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type == null) throw new ArgumentNullException("type");
if (bindingRoot == null) throw new ArgumentNullException("bindingRoot");
if (type.IsInterface || type.IsAbstract) yield break;
if (type == _defaultType)
{
yield return bindingRoot.Bind(_contractType).ToMethod(
ctx =>
{
Type requestedType = ctx.Request.Service;
Type resolution = _cachedBindings.ContainsKey(requestedType)
? _cachedBindings[requestedType]
: _defaultType.MakeGenericType(ctx.GenericArguments);
return ctx.Kernel.Get(resolution);
});
}
else
{
Type interfaceType = ResolveClosingInterface(type);
if (interfaceType != null)
{
yield return bindingRoot.Bind(type).To(_cachedBindings[interfaceType]);
}
}
}
///
/// Resolves the closing interface.
///
/// Type of the target.
///
private 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 != TypeOfObject);
return null;
}
}