• Autofac之类型关联


    前面的学习一直使用的是直接注册类型并不是Autofac已经依赖注入的主要使用方式,最佳的依赖注入与Autofac的使用方式,都是要结合面向接口(抽象)编程的概念的。推崇的是依赖于抽象而不是具体

    public interface IPerson
    {
        void Say();
    }
    
    public class Worker : IPerson
    {
        public void Say()
        {
            Console.WriteLine("工人!");
        }
    }
    
    public class Student : IPerson
    {
        public void Say()
        {
            Console.WriteLine("学生!");
        }
    }
    
    public class AutoFacManager
    {
        IPerson person;
    
        public AutoFacManager(IPerson MyPerson)
        {
            person = MyPerson;
        }
    
        public void Say()
        {
            person.Say();
        }
    }

    使用AS进行关联

    //IPerson类型的服务和Worker的组件连接起来,这个服务可以创建Worker类的实例
    builder.RegisterType<Worker>().As<IPerson>();
    using (var container = builder.Build())
    {
        var obj = container.Resolve<IPerson>();
        obj.Say();
    }

    多关联

    public interface IPerson
    {
        void Say();
    }
    public interface IDuty
    {
        void Write();
    }
    
    public class Worker : IPerson, IDuty
    {
        public void Say()
        {
            Console.WriteLine("工人!");
        }
    
        public void Write()
        {
            Console.WriteLine("我的工作内容是搬砖!");
        }
    }

    一个类可能实现多个接口,如果我们希望Resolve多个接口时获取到的都是那个类型,应该怎么做呢?最容易想到的方式就是直接再注册As一遍就好了。Autofac提供了类似IEnumerable和IQueryable链式编程的方式,如果希望多个接口或类型都与同一个类型进行关联,我们可以直接在表达式后面继续As

    builder.RegisterType<Worker>()
        .As<IPerson>()
        .As<IDuty>();
    using (var container = builder.Build())
    {
        var obj1 = container.Resolve<IPerson>();
        var obj2 = container.Resolve<IDuty>();
        obj1.Say();
        obj2.Write();
    } 

    自关联AsSelf

     不使用As时,RegisterType注册的是什么类型,Resolve就使用什么类型进行获取,但是在使用As后,就只能使用As的类型进行Resolve;但是如果还想在Resolve<Worker>时能够获取到Worker而不抛出异常,应该怎么办呢?在不知道AsSelf方法的情况下,可以在注册时直接As<Worker>,这样就可以了。另一种方式就是AsSelf

    builder.RegisterType<Worker>().As<IPerson>();//这么写获取实例必须使用As类型进行Resolve 
    builder.RegisterType<Worker>().As<IPerson>().AsSelf();//这么写可以使用原类型进行Resolve 
    using (var container = builder.Build())
    {
        var obj1 = container.Resolve<Worker>();//builder.RegisterType<Worker>().As<IPerson>().As<Worker>();或者builder.RegisterType<Worker>().As<IPerson>().AsSelf();都可以
        var obj2 = container.Resolve<IPerson>();//必须builder.RegisterType<Worker>().As<IPerson>();          
        obj1.Say();
        obj2.Say();
    }

    批量关联AsImplementedInerfaces

    之前说到可以通过多个As为一个类型关联多个接口,但是如果实现接口过多代码还是不够简洁,通过AsImplementInterfaces方法,可以让所有注册类型自动与实现的接口进行关联。当然,也正因为这点,在使用AsImplementInterfaces时需要注意,是否真的希望与所有接口都进行关联

    builder.RegisterType<Worker>().AsImplementedInterfaces();
    using (var container = builder.Build())
    {
        var obj1 = container.Resolve<IPerson>();
        var obj2 = container.Resolve<IDuty>();
        obj1.Say();
        obj2.Write();
    }

    类型关联注意点

    一个接口/类型只能与一个类型进行关联,前面我们看到了,可以将一个类型与多个接口进行关联,让多个接口Resolve结果都是同一个类型实例。需要注意的是,这个是不可逆的,也就是一个接口不能与多个类型进行关联,因为这样autofac不知道应该返回哪个类型实例

    builder.RegisterType<Worker>().As<IPerson>();
    builder.RegisterType<Student>().As<IPerson>();
    using (var container = builder.Build())
    {
        var obj = container.Resolve<IPerson>();
        obj.Say();
    }

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

    关联类型与注册类型需要时继承/实现关系或为其本身

    builder.RegisterType<X>().As<Y>();

    当这样进行注册关联时,需要X继承或实现Y,再或者Y就是X类型,否则将在builder调用Build方法时抛出异常。

    1、类型

    类型是描述服务的基本方法

    builder.RegisterType<Worker>().As<IPerson>();  //IPerson类型的服务和Worker的组件连接起来,这个服务可以创建Worker类的实例

    2、名字

    服务可以进一步按名字识别。使用这种方式时,用 Named()注册方法代替As()以指定名字

    builder.RegisterType<Worker>().Named<IPerson>("worker");
    builder.RegisterType<Student>().Named<IPerson>("student");
    using (var container = builder.Build())
    {
        var obj1 = container.ResolveNamed<IPerson>("worker");
        obj1.Say();
        var obj2 = container.ResolveNamed<IPerson>("student");
        obj2.Say();
    }

    3、键

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

    例如,使用枚举作为key:

    public enum State { Worker, Student }
    builder.RegisterType<Worker>().Keyed<IPerson>(State.Worker);
    builder.RegisterType<Student>().Keyed<IPerson>(State.Student);
    using (var container = builder.Build())
    {
        var obj1 = container.ResolveKeyed<IPerson>(State.Worker);
        obj1.Say();
        var obj2 = container.ResolveKeyed<IPerson>(State.Student);
        obj2.Say();
    }

    ResolveKeyd()会导致容器被当做 Service Locator使用,这是不被推荐的。应该使用IIndex type替代。

    IIndex索引,需要using Autofac.Features.Indexed

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

    builder.RegisterType<Student>().Keyed<IPerson>(State.Student);
    using (IContainer container = builder.Build())
    {
        IIndex<State, IPerson> IIndex = container.Resolve<IIndex<State, IPerson>>();
        IPerson p = IIndex[State.Student];
        p.Say();
    }

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

  • 相关阅读:
    嵌入式网络设备一次盲点补报的开发经验(二)
    嵌入式网络设备一次盲点补报的开发经验(一)
    调试lcd时候给linux单板移植tslib
    java 常用的解析工具
    快速上手 Echarts
    alibaba/fastjson 之 JSONPath
    CentOS 7.5 安装Docker 教程
    Java问题-java进程占用内存过高,排查原因
    zabbix问题-cannot create IPC key for path
    rsync服务-部署配置与维护
  • 原文地址:https://www.cnblogs.com/GnailGnepGnaw/p/10753626.html
Copyright © 2020-2023  润新知