2016-09-28 141 views
1

比方說,我有這個類:註冊泛型類型

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

什麼是解決它的好方法?

回答

0

正如我瞭解您的代碼,您需要一種方法將特定的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()); 

取而代之的if (t0 == typeof(Detailed))您可以使用IDictionary<Type, Type>QueryHandlerRegistrationSource的參數。