c# generics ninject

c# - NInject con interfaz genérica



generics (4)

He definido una interfaz y una clase:

public interface IRepository<T> { } public class RoleRepository:IRepository<Domain_RoleInfo> { }

Inyectar aquí:

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

¿Cómo puedo realizar Dependency Injection With Ninject, decir cómo vincular?

He escrito una clase auxiliar como la que se muestra a continuación, funciona bien con una interfaz no genérica. ¿Pero cómo refactorizarla es compatible con la interfaz genérica como se indicó anteriormente?

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


Esto debería ayudar a lograr lo que estás pidiendo.

Primero, definamos dos clases ( InterfaceTypeDefinition y BindingDefinition ).

InterfaceTypeDefinition contiene información sobre un tipo concreto y sus interfaces. El método IsOpenGeneric se define en la clase 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 contiene información sobre la vinculación entre un servicio y una implementación concreta.

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

Segundo, implementemos un método de extensión que recupere la información necesaria.

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

Estas clases ahora se pueden usar para inicializar los enlaces en el módulo.

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


Esto debería funcionar:-

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

dónde:-

IRepository <> es una interfaz de la forma: -

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

Repository <> es una clase de la forma: -

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

Espero que esto ayude :-)


Si importa la extensión de convenciones Ninject, su GenericBindingGenerator debería poder ayudarlo. Agrega soporte para interfaces genéricas.


Solo una pregunta sobre su método FindAndBindInterfaces : dentro del foreach ¿no tiene un problema de "cierre" en la variable intf ? Todavía no estoy seguro de haber entendido cómo funciona el problema del cierre.

De todos modos, solo para estar seguro, creo que deberías cambiar tu foreach a algo así como:

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