NInject with Generic interface

前端 未结 4 672
一向
一向 2020-12-12 16:57

I have defined one interface and one class:

public interface IRepository
{
}

public class RoleRepository:IRepository
{
}


        
相关标签:
4条回答
  • 2020-12-12 17:37

    Just a question on your FindAndBindInterfaces method: inside the foreach don't you have a "closure" problem on the intf variable? I'm still not sure I understood how the closure issue works.

    Anyway, just to be safe, I think that you should change your foreach into something like:

    foreach (Type intf in interfaces)
        {
            var tmp = intf;
            Type t = ts.Where(x => x.GetInterface(tmp.Name) != null).FirstOrDefault();
            if (t != null)
            {
                Bind(intf).To(t).InSingletonScope();
            }
        }
    
    0 讨论(0)
  • 2020-12-12 17:41

    This should help accomplish what you are asking for.

    First let us define two classes (InterfaceTypeDefinition and BindingDefinition).

    InterfaceTypeDefinition holds information about a concrete type and its interfaces. The method IsOpenGeneric is define in the TypeExtensions class.

    public class InterfaceTypeDefinition
    {
        public InterfaceTypeDefinition(Type type)
        {
            Implementation = type;
            Interfaces = type.GetInterfaces();
        }
    
        /// <summary>
        /// The concrete implementation.
        /// </summary>
        public Type Implementation { get; private set; }
    
        /// <summary>
        /// The interfaces implemented by the implementation.
        /// </summary>
        public IEnumerable<Type> Interfaces { get; private set; }
    
        /// <summary>
        /// Returns a value indicating whether the implementation
        /// implements the specified open generic type.
        /// </summary>
        public bool ImplementsOpenGenericTypeOf(Type openGenericType)
        {
            return Interfaces.Any(i => i.IsOpenGeneric(openGenericType));
        }
    
        /// <summary>
        /// Returns the service type for the concrete implementation.
        /// </summary>
        public Type GetService(Type openGenericType)
        {
            return Interfaces.First(i => i.IsOpenGeneric(openGenericType))
                .GetGenericArguments()
                .Select(arguments => openGenericType.MakeGenericType(arguments))
                .First();
        }
    }
    

    BindingDefinition holds information about the binding between a service and a concrete implementation.

    public class BindingDefinition
    {
        public BindingDefinition(
            InterfaceTypeDefinition definition, Type openGenericType)
        {
            Implementation = definition.Implementation;
            Service = definition.GetService(openGenericType);
        }
    
        public Type Implementation { get; private set; }
    
        public Type Service { get; private set; }
    }
    

    Second, let us implement an extension method that retrieves the necessary information.

    public static class TypeExtensions
    {
        public static IEnumerable<BindingDefinition> GetBindingDefinitionOf(
          this IEnumerable<Type> types, Type openGenericType)
        {
            return types.Select(type => new InterfaceTypeDefinition(type))
                .Where(d => d.ImplementsOpenGenericTypeOf(openGenericType))
                .Select(d => new BindingDefinition(d, openGenericType));
        }
    
        public static bool IsOpenGeneric(this Type type, Type openGenericType)
        {
            return type.IsGenericType 
                && type.GetGenericTypeDefinition().IsAssignableFrom(openGenericType);
        }
    }
    

    These classes can now be used to initialize the bindings in the module.

    public class RepositoryModule : NinjectModule
    {
        public override void Load()
        {
            var definitions = Assembly.GetExecutingAssembly().GetTypes()
                .GetBindingDefinitionOf(typeof(IRepository<>));
    
            foreach (var definition in definitions)
            {
                Bind(definition.Service).To(definition.Implementation);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-12 17:41

    If you import the Ninject conventions extension, its GenericBindingGenerator should be able to help you. It adds support for generic interfaces.

    0 讨论(0)
  • 2020-12-12 17:59

    This should work:-

    Bind(typeof(IRepository<>)).To(typeof(Repository<>));
    

    where:-

    IRepository<> is an interface of the form:-

    public interface IRepository<T> where T : class
    {
     //...
    }
    

    Repository<> is a class of the form:-

    public class Repository<T> : IRepository<T> where T : class
    {
      //...
    }
    

    I hope this helps :-)

    0 讨论(0)
提交回复
热议问题