注册泛型类型

本文关键字:泛型类型 注册 | 更新日期: 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的参数