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

Posted lonelyxmas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#依赖注入控制反转IOC实现详解相关的知识,希望对你有一定的参考价值。

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

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;

技术分享图片

技术分享图片
















以上是关于C#依赖注入控制反转IOC实现详解的主要内容,如果未能解决你的问题,请参考以下文章

PHP依赖注入(DI)和控制反转(IoC)详解

详解Spring IoC容器

IOC和DI的区别详解

IOC 控制反转IOC 简介 ( 依赖注入的两种实现方式 | 编译期注入 | 运行期注入 )

Spring -- Spring配置文件详解(Bean实例化的三种方式IoC(控制反转) 与 DI(依赖注入)依赖注入详解)

PHP依赖注入,控制反转,反射Ioc容器和服务提供者各个概念的理解和使用