文档章节

C#依赖注入控制反转IOC实现详解

o
 osc_x4h57ch8
发布于 2018/04/23 23:53
字数 1000
阅读 0
收藏 0

精选30+云产品,助力企业轻松上云!>>>

IOC的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器负责将这些联系在一起。

举个例子,组件A中有类ClassA,组件B中有接口IB和其对应的实现类B1和B2。

那么,现在ClassA需要利用IB接口来做一些事情,例如:

public class ClassA {
public void DoSomething() {
IB b = ???
b.DoWork();
}
}

现在的问题来了,IB b = ??? 中这三个???要写什么代码?是要写成 IB b = new B1(),还是要写成IB b = new B2() ?

不管是哪一种,都会让ClassA强依赖于IB的实现。

在上面这种方案中,ClassA通过new一个B1或B2来实现对IB的依赖的获取,换句话说,ClassA在主动获取依赖。

这样的设计会让ClassA很难扩展,那我们要改良设计:使用依赖注入。上面说到了,问题出在new这里,也就是依赖是Class去主动获取的,那我们就要解决这个问题:不要去主动获取对IB的依赖(通过new),而让这个依赖从ClassA的外面“注入”进来。注入有多种方式,比较常用的一种是通过构造函数注入,那么,我们要把ClassA改成:

public class ClassA {
private IB b;

public ClassA(IB b) {
this.b = b;
}

public DoSomething() {
this.b.DoWork();
}
}

可以看到,通过把IB这个依赖从构造函数中“注”进来后,ClassA就不依赖IB的实现了。还可以发现,这个重构过程中,我们是把"ClassA主动获取对IB的依赖”变成“把对IB的依赖从外部注入到ClassA中”,依赖的方向反转了,所以,依赖注入又称“控制反转”。

IoC框架(如Unity, Autofac,Spring.Net),其中Unity是微软自己封装的,另外可以利用Extnesions.Dependency动态生成类(参考之前的将RFCTable转为List<T>利用依赖注入动态生成类的例子),参考之前的代码

下面以Unity作为介绍:

Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入。Unity可以处理那些从事基于组件的软件工程的开发人员所面对的问题。构建一个成功应用程序的关键是实现非常松散的耦合设计。下面介绍一下c#中使用unity的方法(我是以webapi项目为例,但本例中并没有针对webapi做特殊处理)

新建一个mvc4 webapi项目,下面的例子只用到get方法

用nuget安装unity,如图

新建一个接口类,以及继承该接口的两个类

直接在api/values的get中尝试简单实现unity

using (IUnityContainer container = new UnityContainer())

            {

                container.RegisterType<IBook, BBook>();

                IBook a = container.Resolve<IBook>();

                var strResult = a.Write();

                return strResult;

            }  

然后在浏览器中查看,页面显示的返回值,是BBook的

如果container.RegisterType<IBook, BBook>();中的BBook改为ABook,返回值就是ABook的内容

config中代码如下

在configSections中加入

<section name="unity"

type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />

在configuration中加入

<unity  xmlns="http://schemas.microsoft.com/practices/2010/unity">

    <container>

      <register type="testunity.Models.IBook,testunity" mapTo="testunity.Models.ABook, testunity" />

    </container>

  </unity>

注意 type="testunity.Models.IBook,testunity" mapTo="testunity.Models.ABook, testunity" 

testunity.Models.IBook是命名空间加类名

testunity是程序集的名称

然后cs的代码改成

using (IUnityContainer container = new UnityContainer())

{

    UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

    configuration.Configure(container);

    IBook a = container.Resolve<IBook>();

    var strResult = a.Write();

    return strResult;

}   

在浏览器中可以看到返回结果对应的是config中register的那个类

每次调用都要写IUnityContainer container = new UnityContainer()显然不是好办法

那就把container封装到一个单列类中

简单实现如下

public class ServiceLocator:IServiceProvider

    {

        private readonly IUnityContainer _container;

        private static readonly ServiceLocator instance = new ServiceLocator();

        private ServiceLocator()

        {

            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            _container = new UnityContainer();

            section.Configure(_container);

        }

        public static ServiceLocator Instance

        {

            get { return instance; }

        }

        public object GetService(Type serviceType)

        {

            return _container.Resolve(serviceType);

        }

        public T GetService<T>()

        {

            return _container.Resolve<T>();

        }

    }

cs代码修改如下

IBook a = ServiceLocator.Instance.GetService<IBook>();

var strResult = a.Write();

return strResult;

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

面试必问之mysql基础

mysql存储引擎 如何选择mysql存储引擎 先得了解下各个存储引擎区别 功能 MylSAM MEMORY InnoDB Archive 功能 MylSAM MEMORY InnoDB Archive 存储限制 256TB RAM 64TB None 支持事务 No No Ye...

lipengxs
36分钟前
16
0
错误:将标头发送到客户端后无法设置标头 - Error: Can't set headers after they are sent to the client

问题: I'm fairly new to Node.js and I am having some issues. 我对Node.js相当陌生,遇到了一些问题。 I am using Node.js 4.10 and Express 2.4.3. 我正在使用Node.js 4.10和Express 2......

法国红酒甜
47分钟前
18
0
Spring中事务不生效的几种情况

数据库引擎不支持事务。 没有被Spring管理。 方法不是public的。 自身调用问题。 数据源没有配置事务管理器。 不支持事务。 异常被吃了。 异常类型错误。 事务失效类型: 数据库引擎不支持事...

九分石人
今天
31
0
从Linux内核理解JAVA的NIO

前言 IO 可以简单分为磁盘 IO 和 网络 IO ,磁盘 IO 相对于网络 IO 速度会快一点,本文主要介绍 磁盘 IO ,网络 IO 下周写。 JAVA 对 NIO 抽象为 Channel , Channel 又可以分为 FileChannel ...

万古云霄
今天
22
0
Material Design用在c#的wpf app中

官网:http://materialdesigninxaml.net/ 样式丰富 做网站和手机不粗 个人觉得不适合用在.net framework中,在.net core中应该大有作为。...

齐勇cn
今天
28
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部