2010-02-07 12 views
41

ich eine Schnittstelle und eine Klasse definiert haben:ninject Generic Interface

public interface IRepository<T> 
{ 
} 

public class RoleRepository:IRepository<Domain_RoleInfo> 
{ 
} 

hier Inject:

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

Wie kann ich Dependency Injection mit Ninject durchführen, sagen, wie zu binden?

Ich habe eine Hilfsklasse wie folgt geschrieben, es funktioniert gut mit nicht-generische Schnittstelle.aber wie Refactor es unterstützt generische Schnittstelle wie oben?

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


} 

Antwort

5

Dies sollte helfen zu erreichen, was Sie verlangen. Geben Sie zunächst zwei Klassen ein (InterfaceTypeDefinition und BindingDefinition).

InterfaceTypeDefinition enthält Informationen über einen konkreten Typ und seine Schnittstellen. Die Methode IsOpenGeneric ist in der Klasse TypeExtensions definiert.

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 enthält Informationen über die zwischen einem Dienst und einer konkreten Umsetzung verbindlich.

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

Zweitens implementieren wir eine Erweiterungsmethode, die die erforderlichen Informationen abruft.

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

Diese Klassen können nun verwendet werden, um die Bindung in dem Modul zu initialisieren.

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

Danke. Dies ist genau das, was ich gesucht habe, als ich diese Frage gestellt habe - http://stackoverflow.com/questions/11702477/binding-generic-types-in-ninject-3-0 Es gibt einen Tippfehler in TypeExtensions.GetBindingDefintionOf() - Sie sollten "d" anstelle von "definition" übergeben, wenn Sie die BindingDefinition in der Select-Methode erstellen. – Baldy

78

Dies sollte funktionieren: -

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

wo: -

IRepository <> eine Schnittstelle von der Form: -

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

Repository <> ist eine Klasse, in der Form: -

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

Ich hoffe, das :-)

+0

Wie würde der Konstruktor injizieren aussehen? – chobo2

+0

@ chobo2 siehe Originalbeitrag? – Izmoto

+1

funktioniert es ohne "where T: class"? – Boinst

0

nur eine Frage auf dem FindAndBindInterfaces Methode hilft: in der foreach nicht Sie haben eine „Schließung“ -Problem auf der intf Variable? Ich bin mir immer noch nicht sicher, ob ich verstanden habe, wie das Schließungsproblem funktioniert.

Wie dem auch sei, nur um sicher zu sein, denke ich, dass Sie Ihre foreach in so etwas wie ändern sollte:

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

Wenn Sie die Ninject Konventionen Erweiterung importieren, seine GenericBindingGenerator sollten Sie helfen können. Es fügt Unterstützung für generische Schnittstellen hinzu.

+2

Wie hilft es? –

+0

Ich habe meine Antwort aktualisiert. Es fügt Unterstützung für generische Schnittstellen hinzu. – neontapir