使用autofac为开放泛型条件注册decorator



我有这些开放泛型:

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>的查询注册decorator。我正在注册这样的组件:

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

但是它为所有类型注册了decorator。知道吗?提前谢谢。

不幸的是,Autofac还没有推出这个功能。然而,它可以实现注册来源:

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提供的动态注册来覆盖这些注册。

  • 在这个解决方案中,装饰组件继承了装饰组件的配置(作用域、共享、所有权等)

相关内容

  • 没有找到相关文章

最新更新