【问题标题】:Register adapter without common interface and scanning assemblies无通用接口和扫描组件的套准适配器
【发布时间】:2015-06-22 19:21:06
【问题描述】:

我正在努力实现以下目标:

  1. 扫描特定程序集 (RegisterAssemblyTypes(assembly))。
  2. 过滤到特定的命名空间 (.IsInNamespace("...")),该命名空间将具有独立的接口,没有通用的基本接口。
  3. 将通用适配器注册为通用接口。(.RegisterGeneric(typeof(Adapter<>)).As(typeof(IAdapter<>))
  4. 我需要几个这样的注册,每个集合都将使用 IAdapter<> 和不同的 Adapter<> 实例。

换句话说,IFooIBar 可能在 namespace1 中,IAbc 在 namespace2 中,我想注册:

  • Adapter<IFoo>IAdapter<IFoo>
  • Adapter<IBar>IAdapter<IBar>
  • Adapter2<IAbc>Adapter<IAbc>(customParams)IAdapter<IAbc>

再说一遍,如果我自己扫描程序集以获取接口,那么我相信我可以做类似的事情(未经测试):

Type interfaces[] = ...; // Scan assembly and filter to namespace1

foreach (Type interfaceType in interfaces)
{
    builder
        .Register(context => typeof(Adapter<>).MakeGenericType(interfaceType))
        .As(type => typeof(IAdapter<>).MakeGenericType(interfaceType));
}

interfaces = ...; // Interfaces in namespace2

foreach (Type interfaceType in interfaces)
{
    builder
        .Register(context => typeof(Adapter2<>).MakeGenericType(interfaceType))
        .As(type => typeof(IAdapter<>).MakeGenericType(interfaceType));
}

有什么方法可以使用 Autofac 开箱即用地做到这一点,而无需我自己进行扫描/循环?我看过 Autofac adapter support,但这似乎只适用于通用界面。 RegisterGeneric 也有帮助,但仅限于一种类型的实例。

【问题讨论】:

    标签: c# autofac


    【解决方案1】:

    Autofac 没有内置支持来根据泛型参数的类型解析泛型服务。顺便说一句,您可以使用IRegistrationSource 进行动态注册来做您想做的事情。

    假设你有这些类型:

    namespace A
    {
        interface IFoo { }
    }
    namespace B
    {
        interface IBar { }
    }
    
    interface IAdapter<T> { }
    class Adapter1<T> : IAdapter<T> { }
    class Adapter2<T> : IAdapter<T> { }
    class Foo : A.IFoo { }
    class Bar : B.IBar { }
    

    你想要这样的东西:

    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<Foo>().As<A.IFoo>();
    builder.RegisterType<Bar>().As<B.IBar>();
    
    builder.RegisterGeneric(typeof(Adapter1<>)).As(typeof(IAdapter<>));
    builder.RegisterGeneric(typeof(Adapter2<>)).As(typeof(IAdapter<>));
    
    IContainer container = builder.Build();
    
    var fooAdapter = container.Resolve<IAdapter<A.IFoo>>(); // should return Adapter1<Foo>()
    var barAdapter = container.Resolve<IAdapter<B.IBar>>(); // should return Adapter2<Bar>()
    

    Autofac 将解析IAdapter&lt;T&gt; 时,它无法根据T 的命名空间找到具体的实现。

    IRegistrationSource 将允许您在 Autofac 需要时动态注册一个类型。

    class TestRegistrationSource : IRegistrationSource
    {
        public Boolean IsAdapterForIndividualComponents
        {
            get { return false; }
        }
    
        public IEnumerable<IComponentRegistration> RegistrationsFor(
            Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
        {
            IServiceWithType typedService = service as IServiceWithType;
            if (typedService == null)
            {
                yield break;
            }
            if (!(typedService.ServiceType.IsGenericType 
                  && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IAdapter<>)))
            {
                yield break;
            }
    
            Type t = typedService.ServiceType.GetGenericArguments()[0];
    
            IComponentRegistration registration = 
                RegistrationBuilder.ForDelegate((c, p) => c.ResolveNamed(t.Namespace, typedService.ServiceType, p))
                                   .As(service)
                                   .CreateRegistration();
    
            yield return registration;
        }
    }
    

    这个IRegistrationSource 将在Autofac 需要它时注册一个新的具体实现。当 Autofac 需要 IAdapter&lt;A.Foo&gt; 时,它将输入 TestRegistrationSource,它将注册一个新的 IAdapter&lt;A.Foo&gt; 作为代表,这将解析 IAdapter&lt;T&gt; 的命名通用注册

    为了使TestRegistrationSource 工作,您必须更改Adapter1&lt;T&gt;Adapter2&lt;T&gt; 的注册以使用通用命名注册。

    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<Foo>().As<A.IFoo>();
    builder.RegisterType<Bar>().As<B.IBar>();
    
    builder.RegisterSource(new TestRegistrationSource());
    
    builder.RegisterGeneric(typeof(Adapter1<>)).Named("Namespace.A", typeof(IAdapter<>));
    builder.RegisterGeneric(typeof(Adapter2<>)).Named("Namespace.B", typeof(IAdapter<>));
    
    IContainer container = builder.Build();
    
    var fooAdapter = container.Resolve<IAdapter<A.IFoo>>(); // will return Adapter1<Foo>()
    var barAdapter = container.Resolve<IAdapter<B.IBar>>(); // will return Adapter2<Bar>()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 2017-01-04
      • 2013-12-03
      • 1970-01-01
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多