注册泛型类型
本文关键字:泛型类型 注册 | 更新日期: 2023-09-27 18:09:20
假设我有这样一个类:
public class DetailedQueryHandler<T> : IQueryHandlerAsync<Detailed, T>
where T : CalculationQuery
我可以这样注册:
builder.RegisterType(typeof(DetailedQueryHandler<CalculationWithDealerQuery>))
.As(typeof(IQueryHandlerAsync<Detailed, CalculationWithDealerQuery>));
builder.RegisterType(typeof(DetailedQueryHandler<CalculationQuery>))
.As(typeof(IQueryHandlerAsync<Detailed, CalculationQuery>));
但是我想以更自动化的方式注册它,就像我可以在下面注册IQueryHandlerAsync接口的类型:
var types = ThisAssembly.GetTypes();
builder.RegisterTypes(types)
.Where(t => t.ImplementGenericInterface(t2 => t2 == typeof(IQueryHandlerAsync<,>))
.AsImplementedInterfaces()
和
public interface IQueryHandlerAsync<T, in TI>
public static bool ImplementGenericInterface(this Type type, Func<Type, bool> comparer) {
return type.GetInterfaces().Any(i => i.IsGenericType
&& comparer(i.GetGenericTypeDefinition()));
}
解决这个问题的好方法是什么?
在我理解你的代码时,你需要一种方法将特定的IQueryHandlerAsync
实现与特定的CalculationQuery
相关联。
一种可能的方法是注册你想要的类型,并创建一个AsQueryHandler
方法为你做注册:
public static class ContainerBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TConcreteActivatorData, SingleRegistrationStyle> AsQueryHandler<TLimit, TConcreteActivatorData>(this IRegistrationBuilder<TLimit, TConcreteActivatorData, SingleRegistrationStyle> registration)
where TConcreteActivatorData : IConcreteActivatorData
{
Type queryHandlerType = registration.ActivatorData.Activator.LimitType;
Type queryHandlerRegistrationType = queryHandlerType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryHandlerAsync<,>));
if (queryHandlerRegistrationType == null)
{
throw new ArgumentException($"{queryHandlerType} doesn't implement {typeof(IQueryHandlerAsync<,>).Name} interface");
}
TypedService queryHandlerService = new TypedService(queryHandlerRegistrationType);
return registration.As(queryHandlerService);
}
}
你可以这样使用:
builder.RegisterType<DetailedQueryHandler<CalculationQuery>>()
.AsQueryHandler();
如果您不想手动注册所有类型,则必须进行程序集扫描以根据需要组合所需的类型。
另一种考虑的方法是实现IRegistrationSource
接口。该接口包含一个RegistrationsFor
方法,当Autofac需要一个新组件时将调用该方法。您可以将此接口视为根据需求动态注册组件的一种方式。
public class QueryHandlerRegistrationSource : IRegistrationSource
{
public Boolean IsAdapterForIndividualComponents
{
get
{
return false;
}
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
Type serviceType = (service as IServiceWithType)?.ServiceType;
if (serviceType == null)
{
yield break;
}
if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IQueryHandlerAsync<,>))
{
Type[] argumentTypes = serviceType.GetGenericArguments();
Type t0 = argumentTypes[0];
Type t1 = argumentTypes[1];
if (t0 == typeof(Detailed))
{
IComponentRegistration registration = RegistrationBuilder.ForType(typeof(DetailedQueryHandler<>).MakeGenericType(t1))
.As(service)
.CreateRegistration();
yield return registration;
}
else
{
throw new NotSupportedException();
}
}
}
}
别忘了注册注册源:
builder.RegisterSource(new QueryHandlerRegistrationSource());
可以使用IDictionary<Type, Type>
代替if (t0 == typeof(Detailed))
作为QueryHandlerRegistrationSource
的参数