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","刘先生"));
本篇到这已经完成了,有不对的地方,还希望各位能多多指点,共同学习进步。