Using NInject to bind a generic interface, with a default if a binding for the generic type is not set

后端 未结 3 1725
一向
一向 2021-02-02 02:04

Imagine I have the following classes and interfaces:

public interface IService { }

public class DefaultService : IService { }

public         


        
3条回答
  •  一向
    一向 (楼主)
    2021-02-02 02:36

    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;
        }
    }
    

提交回复
热议问题