2011-06-02 8 views
6

que tengo una clase abstracta:ninject: Enlaces por omisión y específicos para una clase genérica

public abstract class Validator<T> : IValidator 

y un par de clases que implementan esta clase para fines específicos, por ejemplo,

public sealed class NewsValidator : Validator<News> 

Ahora, utilizando Ninject que quiero hacer la inyección de dependencias como la siguiente (este código en particular no está funcionando):

Bind<Validator<News>>().To<NewsValidator>(); 
Bind(typeof(Validator<>)).To(typeof(NullValidator<>)); 

Así que lo que quiero lograr es que

Validator<News> 

Debería estar vinculado a la clase "NewsValidator", pero si se solicita cualquier otra versión no vinculada de esta clase, diga

Validator<Article> 
Validator<SomethingElse> 

que se debe vincular a una clase predeterminada (NullValidator). Sin embargo, el uso del código utilizado anteriormente arroja una excepción, ya que vincula al Validator < Noticias> tanto al NewsValidator como al NullValidator.

¿Cómo podría implementar esto? Los tipos particulares de la clase genérica deberían vincularse a clases individuales. Todos los otros tipos de la clase genérica que no estaban explícitamente vinculados deben estar vinculados a una clase predeterminada.

¡Estaría muy contento con un par de sugerencias! ¡Gracias!

Respuesta

9

Puede crear una implementación personalizada de IMissingBindingResolver.

Cuando el kernel no puede resolver un enlace para un servicio solicitado, delega en el método HandleMissingBinding (esto es cierto para cualquier kernel derivado de KernelBase). El método HandleMissingBinding preguntará a cada solucionador de enlaces faltante si puede crear un enlace para el servicio solicitado. Las consolidaciones devueltas por los resolvedores, si las hay, se agregarán al kernel.

Tenga en cuenta que cualquier enlace creado por una resolución de enlace faltante se agregará al kernel como un enlace implícito. Esto podría tener implicaciones en su aplicación. Por ejemplo, si tiene una combinación de enlaces explícitos e implícitos para un servicio, resolver estos enlaces, es decir, kernel.GetAll<TService>(), solo resuelve enlaces explícitos. Sin embargo, si todas las vinculaciones son implícitas, todas serán resueltas.

Ninject tiene dos implementaciones estándar de IMissingBindingResolver:

vamos a implementar una resolución personalizada para los validadores nulos.

public class MissingValidatorResolver : NinjectComponent, IMissingBindingResolver 
{ 
    public IEnumerable<IBinding> Resolve(
     Multimap<Type, IBinding> bindings, IRequest request) 
    { 
     var service = request.Service; 
     if (!typeof(IValidator).IsAssignableFrom(service)) 
     { 
      return Enumerable.Empty<IBinding>(); 
     } 

     var type = service.GetGenericArguments()[0]; 
     var validatorType = typeof(NullValidator<>).MakeGenericType(type); 

     var binding = new Binding(service) 
     { 
      ProviderCallback = StandardProvider.GetCreationCallback(validatorType) 
     }; 

     return new[] { binding }; 
    } 
} 

Ahora la siguiente prueba (utilizando xUnit.net) pasa.

[Fact] 
public void ShouldResolveNonBoundValidatorDerivedFromValidatorAsNullValidator() 
{ 
    var kernel = new StandardKernel(); 
    kernel.Components.Add<IMissingBindingResolver, MissingValidatorResolver>(); 

    var validator = kernel.Get<Validator<Article>>(); 
    Assert.IsType<NullValidator<Article>>(validator); 
} 
+0

whoa :) Increíble, que funciona como un encanto. ¡¿Cómo lo supiste?! Incluso google no encuentra mucho cuando busca "IMissingBindingResolver".De todos modos, eso es absolutamente perfecto, ¡muchas gracias! – Oliver

Cuestiones relacionadas