2010-02-07 5 views
41

J'ai défini une interface et une classe:ninject avec interface générique

public interface IRepository<T> 
{ 
} 

public class RoleRepository:IRepository<Domain_RoleInfo> 
{ 
} 

Injecter ici:

public RoleService 
{ 
    [Inject] 
    public RoleService(IRepository<Domain_RoleInfo> rep) 
    { 
     _roleRep=rep; 
    } 
} 

Comment puis-je effectuer l'injection de dépendance avec Ninject, dire comment lier?

J'ai écrit une classe d'aide comme ci-dessous, cela fonctionne très bien avec l'interface non-générique. Mais comment refactoriser le support de l'interface générique comme ci-dessus?

public class RegisterNinjectModule : NinjectModule 
{ 
    public override void Load() 
    { 
     BindServices(); 
     BindRepositories(); 
    } 

    private void BindServices() 
    { 

     FindAndBindInterfaces("RealMVC.Service.Interfaces", "RealMVC.Services");    
    } 

    private void BindRepositories() 
    { 
     FindAndBindInterfaces("RealMVC.Repository.Interfaces", "RealMVC.Repositories"); 
    } 

    private void FindAndBindInterfaces(string interfaceAssemblyName, string implAssemblyName) 
    { 
     //Get all interfaces 
     List<Type> interfaces = Assembly.Load(interfaceAssemblyName).GetTypes().AsQueryable().Where(x => x.IsInterface).ToList(); 
     IQueryable<Type> ts = Assembly.Load(implAssemblyName).GetTypes().AsQueryable().Where(x => x.IsClass); 

     foreach (Type intf in interfaces) 
     { 
      Type t = ts.Where(x => x.GetInterface(intf.Name) != null).FirstOrDefault(); 
      if (t != null) 
      { 
       Bind(intf).To(t).InSingletonScope(); 
      } 
     } 
    } 


} 

Répondre

5

Cela devrait aider à accomplir ce que vous demandez.

D'abord, définissons deux classes (InterfaceTypeDefinition et BindingDefinition).

InterfaceTypeDefinition contient des informations sur un type concret et ses interfaces. La méthode IsOpenGeneric est définie dans la classe TypeExtensions.

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 contient des informations sur la liaison entre un service et une mise en œuvre concrète. Deuxièmement, mettons en œuvre une méthode d'extension qui récupère les informations nécessaires.

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

Ces classes peuvent maintenant être utilisées pour initialiser les liaisons dans le 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

Merci. C'est exactement ce que je cherchais quand j'ai posé cette question - http://stackoverflow.com/questions/11702477/binding-generic-types-in-ninject-3-0 Il y a une faute de frappe dans TypeExtensions.GetBindingDefintionOf() - vous devez passer 'd' au lieu de 'definition' lors de la création de BindingDefinition dans la méthode Select. – Baldy

78

Cela devrait fonctionner: -

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

où: -

IRepository <> est une interface de la forme: -

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

dépôt <> est une classe de la forme: -

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

J'espère que cette aide :-)

+0

Comment le constructeur injecterait-il? – chobo2

+0

@ chobo2 voir l'article original? – Izmoto

+1

ça marche sans "où T: class"? – Boinst

0

Une question sur votre FindAndBindInterfaces méthode: à l'intérieur du foreach ne vous avez pas un problème « de fermeture » sur le intf variable? Je ne suis toujours pas sûr d'avoir compris le fonctionnement du problème de fermeture.

Quoi qu'il en soit, juste pour être sûr, je pense que vous devriez changer votre foreach en quelque chose comme:

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(); 
     } 
    } 
2

Si vous importez les conventions Ninject extension, son GenericBindingGenerator devrait être en mesure de vous aider. Il ajoute le support pour les interfaces génériques.

+2

Comment ça aide? –

+0

J'ai mis à jour ma réponse. Il ajoute le support pour les interfaces génériques. – neontapir

Questions connexes