簡體   English   中英

使用autofac條件注冊open-generic的裝飾器

[英]Conditional registering decorator for open-generic with 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);
}

而這個裝飾者:

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

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

我想要的是只為正在實現ICacheableQuery<out TResult>查詢注冊裝飾器。 我正在注冊這樣的組件:

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

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

但它注冊所有類型的裝飾器。 任何想法? 提前致謝。

不幸的是,Autofac還沒有開箱即用的功能。 但是,它可以實現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;
    }
}

樣品用法:

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

請注意

  • 您必須鍵入裝飾組件的注冊,因為(據我所知),無法通過RegistrationSource提供的動態注冊覆蓋這些注冊。

  • 在此解決方案中,裝飾組件繼承了裝飾組件的配置(范圍,共享,所有權等)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM