Autofac初探(一)

前言

 前段时间经历了多轮面试,被几家公司问到了Ioc容器的相关知识,当初只是简略的回答了,其实在以前的项目中用到过,但不知道Ioc容器内部的运行原理或生命周期,以致于回答起来。。。。

今天我重新拾起,从零开始学起,记录自己学习的点滴,加深自己对Ioc容器理解。

什么是控制反转(IOC)、依赖注入(DI)

控制反转(Inversion of  Control)简称IOC,是面向对象编程中的一种设计原则,可以用来降低对象之间的耦合度。Ioc容器把创建依赖对象的控制权交给了容器,由容器注入对象,而传统的都是在类的内部创建对象,从而导致类与类之间高耦合。

依赖注入(Dependency Injection)是组件之间依赖关系由容器在运行期决定。通俗的说,由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

传统的方式

我们以数据库访问为例,一个是Sqlserver类,一个是Oracle类,当我们需要调用时可以选择哪种类型来访问数据库。

 public interface IDataSource
    {
        /// <summary>
        /// 获取数据库数据
        /// </summary>
        string GetData();
    }
public class Sqlserver: IDataSource
    {
        public string GetData()
        {
            return "这里是SQLSERVER数据库,数据获取成功!";
        }
    }
 public class Oracle : IDataSource
    {
        public string GetData()
        {
            return "这里是Oracle数据库,数据获取成功!";
        }
    }

  调用时

static void Main(string[] args)
        {
            IDataSource ds = new Sqlserver();

            Console.WriteLine(ds.GetData());

            Console.ReadLine();
        }

 然后我们进行代码改进,增加一个ManagerDB类,在构造函数中传入IDataSource实现对象,  就会自动创建对应的对象。

public class ManagerDB
    {
        public IDataSource _dataSource { get; set; }

        public ManagerDB(IDataSource dataSource)
        {
            _dataSource = dataSource;
        }
        public void  DbList()
        {
            _dataSource.GetData();
        }   
    }

  调用

   ManagerDB managerDB = new ManagerDB(new Sqlserver());
   managerDB.DbList();

 Autofac构造函数注入

 1. 在项目中通过NuGet程序包引入AutoFac。

2. 因本应用程序采用的是MVC,我们在Web项目下创建一个AutoFacManager类。

 public class AutoFacManager
    {
        public static IContainer container { get; set; }
        public static void RegisterAutoFac()
        {
            var builder = new ContainerBuilder();
            
            builder.RegisterType<Sqlserver>().As<IDataSource>();

            using (container = builder.Build())
            {
                var user = container.Resolve<IDataSource>();
                user.GetData();
            }
          
        }
    }

 3.在Global文件中调用即可。

注入说明

1.  builder.RegisterType<Object>().As<Iobject>(): 注入类型与实例,如上面代码中注入的是IDataSource接口与Sqlserver的实例
2. IContainer.Resolve<T>(); 解析接口的实例也可理解为得到注入的实例。 如以下代码是得到Sqlserver的实例
   public static void RegisterAutoFac()
        {
            var builder = new ContainerBuilder();
             
            builder.RegisterType<Sqlserver>().As<IDataSource>();
 
            using (container = builder.Build())
            {
                var user = container.Resolve<IDataSource>();
                user.GetData();
            }      
        }
3. builder.RegisterType<Object>().Named<Iobject>(string name): 当一个接口注入不同的实例时,例如:IDataSource同时可注入Sqlserver与Oracle,为了区分多个实例我们可以取名来区分。

     public static void RegisterAutoFac()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Sqlserver>().Named<IDataSource>("Sqlserver");
            builder.RegisterType<Oracle>().Named<IDataSource>("Oracle");
            using (container = builder.Build())
            {
                var sqlserver = container.ResolveNamed<IDataSource>("Sqlserver");
                sqlserver.GetData();
                var oracle = container.ResolveNamed<IDataSource>("Oracle");
                oracle.GetData();
            }
        }
4. IContainer.ResolveNamed<IObject>(string name):解析某个接口的“命名实例”。例如上面的红色代码
5. builder.RegisterType<Object>().InstancePerDependency():用于控制对象的生命周期,每次加载实例时都是新建一个实例,默认就是这种方式
6. builder.RegisterType<Object>().SingleInstance():用于控制对象的生命周期,每次加载实例时都是返回同一个实例
7. IContainer.Resolve<T>(NamedParameter namedParameter):在解析实例T时给其赋值,这个就是给你定义的方法的参数传值
修改:我们为ManagerDB构造函数加入Name参数
 
  public class ManagerDB
    {
        public IDataSource _dataSource { get; set; }
        public string Name;
 
        public ManagerDB(IDataSource dataSource, string name)
        {
            _dataSource = dataSource;
            Name = name;
        }
        public string DbList()
        {
            return Name + "" + _dataSource.GetData();
        }
 
    }
 
调用: container.Resolve<ManagerDB>(new NamedParameter("name","刘先生"));

 本篇到这已经完成了,有不对的地方,还希望各位能多多指点,共同学习进步。

posted @ 2020-05-28 16:45  编程老男孩  阅读(231)  评论(0编辑  收藏  举报