依赖倒置?控制反转(IOC)? 依赖注入(DI)?

你是否还在被这些名词所困扰,是否看了大量理论文章后还是一知半解了?

今天我想结合实际项目,和正在迷惑中的新手朋友一起来学习和总结依赖注入Autofac的使用和理解。

依赖注入粗暴理解

依赖: 

public class A
{
public A(B b)
{
// do something
}
}

这样的代码,估计没有程序猿不曾使用。

A类实例化的时候需要一个B的对象作为构造函数的参数,那么A就依赖B,这就叫依赖。

当然,不用构造函数的方式,在A类内部去new一个B,其实也是一样存在A依赖B。

注入:

看到“注入”一词,第一想到的是不是注射器?哈哈,还生活在童年阴影中。 结合一下“打针”这个场景来简单理解下依赖注入。
医生使用注射器(Autofac),将药物(依赖=类对象),注入到血管(其他类中)。

Autofac的基本使用

搭建项目

创建一个MVC项目,通过Nuget直接添加Autofac。

注入类本身.AsSelf()

    public class TestController : Controller
{
private readonly InjectionTestService _testService; public TestController(InjectionTestService testService)
{
_testService = testService;
} public ActionResult Index()
{
ViewBag.TestValue = _testService.Test();
return View();
}
}
    public class InjectionTestService : IService
{
public string Test()
{
return "Success";
}
}

在Global.asax中加入依赖注入的注册代码

            // 创建一个容器
var builder = new ContainerBuilder();
// 注册所有的Controller
builder.RegisterControllers(Assembly.GetExecutingAssembly());
// RegisterType方式:
builder.RegisterType<InjectionTestService>().AsSelf().InstancePerDependency();
// Register方式:
builder.Register(c => new InjectionTestService()).AsSelf().InstancePerDependency(); // 自动注入的方式,不需要知道具体类的名称 /* BuildManager.GetReferencedAssemblies()
* 程序集的集合,包含 Web.config 文件的 assemblies 元素中指定的程序集、
* 从 App_Code 目录中的自定义代码生成的程序集以及其他顶级文件夹中的程序集。
*/ // 获取包含继承了IService接口类的程序集
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>()
.Where(
assembly =>
assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) !=
null
); // RegisterAssemblyTypes 注册程序集
var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();
if (enumerable.Any())
{
builder.RegisterAssemblyTypes(enumerable)
.Where(type => type.GetInterfaces().Contains(typeof(IService))).AsSelf().InstancePerDependency();
} // 把容器装入到微软默认的依赖注入容器中
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

为接口注入具体类.AsImplementedInterfaces()

    public class TestController : Controller
{
private readonly IService _testService;
public TestController(IService testService)
{
_testService = testService;
} public ActionResult Index()
{
ViewBag.TestValue = _testService.Test();
return View();
}
}
            // Register 方式指定具体类
builder.Register(c => new InjectionTestService()).As<IService>().InstancePerDependency(); // RegisterType 方式指定具体类
builder.RegisterType<InjectionTestService>().As<IService>().InstancePerDependency(); // 自动注册的方式 // 获取包含继承了IService接口类的程序集
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>()
.Where(
assembly =>
assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) !=
null
); // RegisterAssemblyTypes 注册程序集
var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();
if (enumerable.Any())
{
builder.RegisterAssemblyTypes(enumerable)
.Where(type => type.GetInterfaces().Contains(typeof(IService))).AsImplementedInterfaces().InstancePerDependency();
}

利用Named自动注入依赖类

需求场景说明:

有A、B、C三个短信平台提供发送短信业务;

分别有三个短信平台的实现类,AMessage,BMessage,CMessage;

客户端在不同时段选取不同平台发送短信。

常规简单处理方式

新建三个服务类,AMsgService,BMsgService,CMsgService。
在客户端通过 if else 的方式判断要选用哪个短信平台,然后new服务类对象,再调用Send方法发送短信。

缺点

如果有新的短信平台D加入的话,必须新建一个DSendMsgService,然后修改客户端if else 代码。

改造

抽象一个短信平台的接口
    public interface IMessage
{
decimal QueryBalance();
bool Send(string msg);
int TotalSend(DateTime? startDate, DateTime? endDate);
}

具体实现类

    [MessagePlatform(Enums.MPlatform.A平台)]
public class ASendMessageService : IMessage
{
public decimal QueryBalance()
{
return ;
} public bool Send(string msg)
{
return true;
} public int TotalSend(DateTime? startDate, DateTime? endDate)
{
return ;
}
}

类有一个自定义属性标签MessagePlatform,这个是干嘛了? 是为了给这个类做一个标记,结合Named使用,实现自动注入。

    public class TestController : Controller
{
private Func<int, IMessage> _factory;
public TestController(Func<int, IMessage> factory)
{
_factory = factory;
} public ActionResult Index()
{
var retult = _factory((int)Enums.MPlatform.A平台).Send("去你的吧");
return View(retult);
}
}

构造函数参数居然是一个func的委托?

这个factory传入参数是一个int(定义好的短信平台枚举值),就可以拿到这个短信平台具体的实现类?

没错,autofac就是这么任性。

            builder.RegisterType<ASendMessageService>().Named<IMessage>(
(
// 获取类自定义属性
typeof(ASendMessageService).GetCustomAttributes(typeof(MessagePlatformAttribute), false).FirstOrDefault()
as MessagePlatformAttribute ).platform.ToString()
).InstancePerRequest(); builder.Register<Func<int, IMessage>>(c =>
{
var ic = c.Resolve<IComponentContext>();
return name => ic.ResolveNamed<IMessage>(name.ToString());
});

疑问:

上面只是给 ASendMessageService类实现了自动注入,那么BSendMessageService,CSendMessageService怎么办了,不可能都去复制一段注入的配置代码吧?

            typeof(IMessage).Assembly.GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IMessage)))
.ForEach(type =>
{
// 注册type
});

如果你有些实现类不在IMessge这个程序集下,那就不能这么写了,要结合具体项目情况来调整代码。

总结

1.依赖注入的目的是为了解耦。

2.不依赖于具体类,而依赖抽象类或者接口,这叫依赖倒置。

3.控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。

4. 微软的DependencyResolver如何创建controller 【后续学习】

Autofac创建类的生命周期

1、InstancePerDependency

对每一个依赖或每一次调用创建一个新的唯一的实例。这也是默认的创建实例的方式。

官方文档解释:Configure the component so that every dependent component or call to Resolve() gets a new, unique instance (default.)

2、InstancePerLifetimeScope

在一个生命周期域中,每一个依赖或调用创建一个单一的共享的实例,且每一个不同的生命周期域,实例是唯一的,不共享的。

官方文档解释:Configure the component so that every dependent component or call to Resolve() within a single ILifetimeScope gets the same, shared instance. Dependent components in different lifetime scopes will get different instances.

3、InstancePerMatchingLifetimeScope

在一个做标识的生命周期域中,每一个依赖或调用创建一个单一的共享的实例。打了标识了的生命周期域中的子标识域中可以共享父级域中的实例。若在整个继承层次中没有找到打标识的生命周期域,则会抛出异常:DependencyResolutionException

官方文档解释:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope tagged with any of the provided tags value gets the same, shared instance. Dependent components in lifetime scopes that are children of the tagged scope will share the parent's instance. If no appropriately tagged scope can be found in the hierarchy an DependencyResolutionException is thrown.

4、InstancePerOwned

在一个生命周期域中所拥有的实例创建的生命周期中,每一个依赖组件或调用Resolve()方法创建一个单一的共享的实例,并且子生命周期域共享父生命周期域中的实例。若在继承层级中没有发现合适的拥有子实例的生命周期域,则抛出异常:DependencyResolutionException

官方文档解释:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope created by an owned instance gets the same, shared instance. Dependent components in lifetime scopes that are children of the owned instance scope will share the parent's instance. If no appropriate owned instance scope can be found in the hierarchy an DependencyResolutionException is thrown.

5、SingleInstance

每一次依赖组件或调用Resolve()方法都会得到一个相同的共享的实例。其实就是单例模式。

官方文档解释:Configure the component so that every dependent component or call to Resolve() gets the same, shared instance.

6、InstancePerHttpRequest  (新版autofac建议使用InstancePerRequest)

在一次Http请求上下文中,共享一个组件实例。仅适用于asp.net mvc开发。
官方文档解释:Share one instance of the component within the context of a single HTTP request.
 参考文档:
https://stackoverflow.com/questions/2888621/autofacs-funct-to-resolve-named-service
http://blog.csdn.net/dhx20022889/article/details/9061483
 

本文博客园地址:http://www.cnblogs.com/struggle999/p/6986903.html 
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
 

依赖注入之Autofac使用总结的更多相关文章

  1. 大比速:remoting、WCF(http)、WCF(tcp)、WCF(RESTful)、asp.net core(RESTful) .net core 控制台程序使用依赖注入(Autofac)

    大比速:remoting.WCF(http).WCF(tcp).WCF(RESTful).asp.net core(RESTful) 近来在考虑一个服务选型,dotnet提供了众多的远程服务形式.在只 ...

  2. ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用

    上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在Web ...

  3. ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用

    话不多说,直入主题看我们的解决方案结构: 分别对上面的工程进行简单的说明: 1.TianYa.DotNetShare.Model:为demo的实体层 2.TianYa.DotNetShare.Repo ...

  4. 依赖注入容器Autofac的详解

    Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成,并且开源,Autofac的主要特性如下: 1,灵活的组件实例化:Aut ...

  5. 依赖注入容器Autofac与MVC集成

    Autofac是应用于.Net平台的依赖注入(DI,Dependency Injection)容器,具有贴近.契合C#语言的特点.随着应用系统的日益庞大与复杂,使用Autofac容器来管理组件之间的关 ...

  6. webapi框架搭建-依赖注入之autofac

    前言 c#的依赖注入框架有unity.autofac,两个博主都用过,感觉unity比较简单而autofac的功能相对更丰富(自然也更复杂一点),本篇将基于前几篇已经创建好的webapi项目,引入au ...

  7. 依赖注入(二)Autofac简单使用

    Autofac简单使用 源码下载传上源码,终于学会传文件了. 首先 还是那句话:“不要信我,否则你死得很惨!”. C#常见的依赖注入容器 IoC in .NET part 1: Autofac IoC ...

  8. 深入浅出依赖注入容器——Autofac

    1.写在前面 相信大家对IOC和DI都耳熟能详,它们在项目里面带来的便利大家也都知道,微软新出的.NetCore也大量采用了这种手法. 如今.NetCore也是大势所趋了,基本上以.Net为技术主导的 ...

  9. 依赖注入之AutoFac

    一 .IoC框架AutoFac简介 IoC即控制反转(Inversion of Control),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(De ...

随机推荐

  1. [ext4] 磁盘布局 - extent tree

    传统的类Unix文件系统,比如Ext3,都是使用一个间接数据块映射表来记录每一个数据块的分配情况的.但是这种机制对于超大文件的存储是有缺陷的,特别是当对超大文件进行删除和截断操作时.映射表会对每一个数 ...

  2. [内存管理]连续内存分配器(CMA)概述

    作者:Younger Liu, 本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可. 原文地址:http://lwn.net/Articles/396657/ 1 ...

  3. O(nlogn)实现LCS与LIS

    序: LIS与LCS分别是求一个序列的最长不下降序列序列与两个序列的最长公共子序列. 朴素法都可以以O(n^2)实现. LCS借助LIS实现O(nlogn)的复杂度,而LIS则是通过二分搜索将复杂度从 ...

  4. python3 selenium 随机选择同一类型下的某一个元素

    使用场景: 如上图所示,有时候,我们测试的时候,不会每个方向都选择一遍,也不能每次都选择一个方向,这个时候就需要每次运行用例的时候,随机选择一个方向来测试 使用方法: random.randint() ...

  5. Docker - 手动迁移镜像

    在没有Docker Registry时,可以通过docker save和docker load命令完成镜像迁移的过程,先将镜像保存为压缩包,然后在其他位置再加载压缩包. 将镜像保存为压缩包文件 [ro ...

  6. json、xml和java对象之间的转化

    其实从面相对象的角度来理解这个问题,就会很清晰.java中的一切皆对象即把世间万物(Everything in the world)看做java对象,任何处理不了的问题都可以先转化成java对象在做处 ...

  7. JavaScript知识点整理(一)

    JavaScript知识点(一)包括 数据类型.表达式和运算符.语句.对象.数组. 一.数据类型 1) js中6种数据类型:弱类型特性 5种原始类型:number(数字).string(字符串).bo ...

  8. [刷题]算法竞赛入门经典 3-7/UVa1368 3-8/UVa202 3-9/UVa10340

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 都是<算法竞赛入门经典(第二版)>的题目,标题上没写(第二版) 题目:算法竞赛入门经典 3-7/UVa13 ...

  9. Java学习笔记——排序算法之希尔排序(Shell Sort)

    落日楼头,断鸿声里,江南游子.把吴钩看了,栏杆拍遍,无人会,登临意. --水龙吟·登建康赏心亭 希尔算法是希尔(D.L.Shell)于1959年提出的一种排序算法.是第一个时间复杂度突破O(n²)的算 ...

  10. 新手在WindowsServer2016上安装ExchangeServer2016时的几点注意要点。

    这两天试着在WindowsServer2016上安装ExchangeServer2016,遇到了两个头疼的问题,还好几经搜索加摸索终于把问题解决了,现在把经验分享出来,给遇到同样的问题的人以参考.在W ...