我有这些开放泛型:
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提供的动态注册来覆盖这些注册。
在这个解决方案中,装饰组件继承了装饰组件的配置(作用域、共享、所有权等)