2015-03-01 4 views
3

Je ces open-génériques:décorateur enregistrement conditionnel pour open-générique avec autofac

public interface IQuery<out TResult> {} 

public interface ICacheableQuery<out TResult> : IQuery<TResult> { 
    string CacheKey { get; } 
} 

public interface IQueryHandler<in TQuery, out TResult> 
    where TQuery : IQuery<TResult> { 
    TResult Handle(TQuery query); 
} 

et ce décorateur unique:

public class CacheableQueryHandlerDecorator<TQuery, TResult> 
    : IQueryHandler<TQuery, TResult> 
    where TQuery : ICacheableQuery<TResult> { 

    public TResult Handle(TQuery query) { 
     // doing stuffs.... 
    } 
} 

Ce que je veux est d'enregistrer décoratrice que pour les requêtes qui sont mettant en œuvre ICacheableQuery<out TResult>. J'enregistre des composants comme ceci:

builder.RegisterAssemblyTypes(assemblies) 
     .AsClosedTypesOf(typeof (IQueryHandler<,>)) 
     .AsImplementedInterfaces() 
     .Named("queryHandler",typeof(IQueryHandler<,>)); 

builder.RegisterGenericDecorator(
    typeof(CacheableQueryHandlerDecorator<,>), 
    typeof(IQueryHandler<,>), 
    fromKey: "queryHandler"); 

Mais il enregistre le décorateur pour tous les types. Une idée? Merci d'avance.

+2

connexes: https://stackoverflow.com/questions/28727607/autofac-registergenericdecorator -not-travail-avec-décorateur-ayant-type-constrai – Steven

+0

@Steven merci beaucoup. en fait, j'allais juste au projet d'injection simple et supprimer autofac;) acclamations –

Répondre

0

Malheureusement, Autofac n'a pas cette fonctionnalité prête à l'emploi. Cependant, il peut être réalisé la mise en œuvre d'un RegistrationSource:

public interface IGenericDecoratorRegistrationBuilder : IHideObjectMembers 
{ 
    IGenericDecoratorRegistrationBuilder Decorator(Type decoratorType, Func<Type, bool> filter = null, Func<Type, IEnumerable<Parameter>> paramsGetter = null); 
} 

public static class GenericDecorators 
{  
    public class GenericDecoratorRegistration 
    { 
     public Type Type; 
     public Func<Type, bool> Filter; 
     public Func<Type, IEnumerable<Parameter>> ParamsGetter; 
    } 

    class GenericDecoratorRegistrationBuilder : IGenericDecoratorRegistrationBuilder 
    { 
     readonly List<GenericDecoratorRegistration> decorators = new List<GenericDecoratorRegistration>(); 

     public IEnumerable<GenericDecoratorRegistration> Decorators 
     { 
      get { return decorators; } 
     } 

     public IGenericDecoratorRegistrationBuilder Decorator(Type decoratorType, Func<Type, bool> filter, Func<Type, IEnumerable<Parameter>> paramsGetter) 
     { 
      if (decoratorType == null) 
       throw new ArgumentNullException("decoratorType"); 

      if (!decoratorType.IsGenericTypeDefinition) 
       throw new ArgumentException(null, "decoratorType"); 

      var decorator = new GenericDecoratorRegistration 
      { 
       Type = decoratorType, 
       Filter = filter, 
       ParamsGetter = paramsGetter 
      }; 

      decorators.Add(decorator); 

      return this; 
     } 
    } 

    class GenericDecoratorRegistrationSource : IRegistrationSource 
    { 
     readonly Type decoratedType; 
     readonly IEnumerable<GenericDecoratorRegistration> decorators; 
     readonly object fromKey; 
     readonly object toKey; 

     public GenericDecoratorRegistrationSource(Type decoratedType, IEnumerable<GenericDecoratorRegistration> decorators, object fromKey, object toKey) 
     { 
      this.decoratedType = decoratedType; 
      this.decorators = decorators; 
      this.fromKey = fromKey; 
      this.toKey = toKey; 
     } 

     public bool IsAdapterForIndividualComponents 
     { 
      get { return true; } 
     } 

     public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) 
     { 
      var swt = service as IServiceWithType; 
      KeyedService ks; 
      if (swt == null || 
       (ks = new KeyedService(fromKey, swt.ServiceType)) == service || 
       !swt.ServiceType.IsGenericType || swt.ServiceType.GetGenericTypeDefinition() != decoratedType) 
       return Enumerable.Empty<IComponentRegistration>(); 

      return registrationAccessor(ks).Select(cr => new ComponentRegistration(
        Guid.NewGuid(), 
        BuildActivator(cr, swt), 
        cr.Lifetime, 
        cr.Sharing, 
        cr.Ownership, 
        new[] { toKey != null ? (Service)new KeyedService(toKey, swt.ServiceType) : new TypedService(swt.ServiceType) }, 
        cr.Metadata, 
        cr)); 
     } 

     DelegateActivator BuildActivator(IComponentRegistration cr, IServiceWithType swt) 
     { 
      var limitType = cr.Activator.LimitType; 
      var actualDecorators = decorators 
       .Where(d => d.Filter != null ? d.Filter(limitType) : true) 
       .Select(d => new { Type = d.Type, Parameters = d.ParamsGetter != null ? d.ParamsGetter(limitType) : Enumerable.Empty<Parameter>() }) 
       .ToArray(); 

      return new DelegateActivator(cr.Activator.LimitType, (ctx, p) => 
      { 
       var typeArgs = swt.ServiceType.GetGenericArguments(); 
       var service = ctx.ResolveKeyed(fromKey, swt.ServiceType); 

       foreach (var decorator in actualDecorators) 
       { 
        var decoratorType = decorator.Type.MakeGenericType(typeArgs); 
        var @params = decorator.Parameters.Concat(new[] { new TypedParameter(swt.ServiceType, service) }); 
        var activator = new ReflectionActivator(decoratorType, new DefaultConstructorFinder(), new MostParametersConstructorSelector(), 
         @params, Enumerable.Empty<Parameter>()); 
        service = activator.ActivateInstance(ctx, @params); 
       } 

       return service; 
      }); 
     } 
    } 

    public static IGenericDecoratorRegistrationBuilder RegisterGenericDecorators(this ContainerBuilder builder, Type decoratedServiceType, object fromKey, object toKey = null) 
    { 
     if (builder == null) 
      throw new ArgumentNullException("builder"); 

     if (decoratedServiceType == null) 
      throw new ArgumentNullException("decoratedServiceType"); 

     if (!decoratedServiceType.IsGenericTypeDefinition) 
      throw new ArgumentException(null, "decoratedServiceType"); 

     var rb = new GenericDecoratorRegistrationBuilder(); 
     builder.RegisterCallback(cr => cr.AddRegistrationSource(new GenericDecoratorRegistrationSource(decoratedServiceType, rb.Decorators, fromKey, toKey))); 

     return rb; 
    } 
} 

Exemple d'utilisation:

public interface IGeneric<T> 
{ 
    void SomeMethod(); 
} 

class IntImpl : IGeneric<int> 
{ 
    public void SomeMethod() { } 
} 

class StringImpl : IGeneric<string> 
{ 
    public void SomeMethod() { } 
} 

class GenericDecorator<T> : IGeneric<T> 
{ 
    IGeneric<T> target; 

    public GenericDecorator(IGeneric<T> target) 
    { 
     this.target = target; 
    } 

    public void SomeMethod() 
    { 
     target.SomeMethod(); 
    } 
} 

static void Configure(ContainerBuilder builder) 
{ 
    builder.RegisterType<IntImpl>().Named<IGeneric<int>>("generic"); 
    builder.RegisterType<StringImpl>().Named<IGeneric<string>>("generic"); 

    builder.RegisterGenericDecorators(typeof(IGeneric<>), "generic") 
     // applying decorator to IGeneric<string> only 
     .Decorator(typeof(GenericDecorator<>), t => typeof(IGeneric<string>).IsAssignableFrom(t)); 
    } 

S'il vous plaît noter

  • Vous devez saisir les enregistrements de composants décorés parce que (pour autant que je savoir) il n'y a aucun moyen de remplacer ces enregistrements dynamiques par RegistrationSource.

  • Dans cette solution, le composant décoré hérite de la configuration de celle décorée (de cadrage, le partage, la propriété, etc.)