• IoC容器Autofac正篇之类型关联(服务暴露)(七)


    类型关联

        类型关联就是将类挂载到接口(一个或多个)上去,以方便外部以统一的方式进行调用(看下例)。

    一.As关联

        我们在进行手动关联时,基本都是使用As进行关联的.

    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
                
            builder.RegisterType<Class1>().As<IInterface>();
    
            var container = builder.Build();
    
            IInterface inter = container.Resolve<IInterface>();
    
            Console.WriteLine(inter.Id);
    
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }
    
    interface IInterface
    {
        Guid Id { get; }
    }
    
    class Class1 : IInterface
    {
        private Guid _id;
    
        public Guid Id
        {
            get { return _id; }
        }
    } 

    从代码中可以看到,我们直接在类型注册后加了一句As<…>(),然后在使用Resolve时也是用的As的类型。

    之前是直接RegisterType注册的类型是Class1,Resolve时也是直接用Class1。

    而现在注册的虽然还是Class1,但是获取时却是用IInterface且最后获取到的实例类型是Class1。

    这样看有点绕,但我们可以理解为注册了IInterface,但是为IInterface指定了实现。好处在于我们如果希望更改IInterface的实现,只需要修改注册的代码,而不需要修改获取处以及后续使用IInterface实例的代码

      多关联   一个类可能实现多个接口,如果我们希望Resolve多个接口时获取到的都是那个类型,应该怎么做呢?如果希望多个接口或类型都与同一个类型进行关联,我们可以直接再表达式后面继续As:builder.RegisterType<C1>().As<I1>().As<I2>().As<I3>,如此,Resolve<I1>、Resolve<I2>、Resolve<I3>获取到的都是C1类型实例。

    二.自关联AsSelf 

       不使用As时,RegisterType注册的是什么类型,Resolve就使用什么类型获取,但使用As后就只能使用As的类型进行Resolve。比如前面的例子中,只能够Resolve<IInterface>,而不能Resolve<Class1>,否则抛出异常。但如想在Resolve<Class1>时能够获取到Class1而不抛出异常,应该怎么办呢?

    // 这两句代码效果相同
    builder.RegisterType<Class1>().As<IInterface>().As<Class1>();
    builder.RegisterType<Class1>().As<IInterface>().AsSelf();

    三 批量关联AsImplementedInerfaces

    AsImplementedInterfaces也就是直接与类型实现的接口进行类型关联

    interface I1 { }
    interface I2 { }
    interface I3 { }
    interface I4 { }
    interface I5 { }
    interface I6 { }
    interface I7 { }
    
    class C1 : I1, I2, I3, I4, I5, I6, I7
    {
    }
    

      一个类型实现了7个接口,然后我们希望Resolve这七个中任何一个接口,都能获取到C1实例,多关联代码可以简写为:

    builder.RegisterType<C1>()
            .As<I1>().As<I2>()
            .As<I3>().As<I4>()
            .As<I5>().As<I6>()
            .As<I7>();
    

      然而在有AsImplementInterfaces方法后,就能够非常简单:

    builder.RegisterType<C1>().AsImplementedInterfaces();
    

      在程序集注册这种方式中,AsImplementInterfaces更能显示出威力,程序集注册这种方式中,都是批量注册类型的,批量注册的这些类型,它们可能都实现了不同的接口,这样我们没办法为它们一一关联接口,但是通过AsImplementInterfaces方法,可以让所有注册类型自动与实现的接口进行关联。当然,也正因为这点,在使用AsImplementInterfaces时需要注意,是否真的希望与所有接口都进行关联。

    四 总结(3中关联方式)

     a.使用AS关联时一个接口只能与一个类型进行关联

     前面将一个类型与多个接口进行关联,让多个接口Resolve结果都是同一个类型实例。这个是不可逆的,也就是一个接口不能与多个类型进行关联,因为这样autofac不知道应该返回哪个类型实例。代码实例:

    builder.RegisterType<C1>().As<I>(); // class C1 : I
    builder.RegisterType<C2>().As<I>(); // class C2 : I
    

      按上面的代码,最后实际与I接口关联的类型是C2,autofac中按注册顺序,后面注册的会覆盖前面注册的。如果想要阻止这种默认行为,可以在As方法调用用继续调用PreserveExistingDefaults方法,这样,如果之前该接口/类型已经进行关联注册,则此次关联无效:

    builder.RegisterType<C1>().As<I>(); // class C1 : I
    builder.RegisterType<C2>().As<I>().PreserveExistingDefaults(); // class C2 : I
    

    上面代码通过Resolve<I>()获取到C1类型实例。注意c1需要实现或继承I

    这里说的一个接口不能关联多个类型,是针对这种常用的注册及关联。其实可以通过Named<>、Meta<>这种方式进行多关联

    b.一个接口与多个类型关联

    builder.RegisterType<Worker>().Named<IPerson>("worker");
    builder.RegisterType<Student>().Named<IPerson>("student");

    使用Name可以检索服务创建实例:

     IPerson p = container.ResolveNamed<IPerson>("worker");

      ResolveNamed()只是Resolve()的简单重载,指定名字的服务其实是指定键的服务的简单版本。

    c.键

      有Name的方式很方便,但是值支持字符串,但有时候我们可能需要通过其他类型作键。

      例如,使用枚举作为key:

      public enum DeviceState { Worker, Student }

      使用key注册服务,通过Keyed<T>()方法:

      builder.RegisterType<Student>().Keyed<IPerson>(DeviceState.Student);

     IIndex索引

     Autofac.Features.Indexed.IIndex<K,V>是Autofac自动实现的一个关联类型。component可以使用IIndex<K,V>作为参数的构造函数从基于键的服务中选择需要的实现。

       builder.RegisterType<Student>().Keyed<IPerson>(DeviceState.Student);
        using (IContainer container = builder.Build())
        {
            IIndex<DeviceState, IPerson> IIndex = container.Resolve<IIndex<DeviceState, IPerson>>();
            IPerson p = IIndex[DeviceState.Student];
            p.Say();  //输出我是一个学生
        } 

      IIndex中第一个泛型参数要跟注册时一致,在例子中是DeviceState枚举。其他两种注册方法没有这样的索引查找功能,这也是为什么设计者推荐Keyed注册的原因之一。

  • 相关阅读:
    (转)swc使用
    (转)AS3中的反射相关
    AS获取url参数
    (转)深入理解Flash Player的安全域(Security Domains)
    (转)html<embed>标签和url向Flash传flashvars值
    (转)ApplicationDomain
    灰度发布
    (转)flex中使用swc实现更好的界面代码分离
    (转)深入理解Flash Player的应用程序域(Application Domains)
    嵌入式系统可执行文件格式
  • 原文地址:https://www.cnblogs.com/tiantianle/p/5194027.html
Copyright © 2020-2023  润新知