控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。
IOC模式,系统中通过引入实现了IOC模式的IOC容器,即可由IOC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码。
Martin Fowler在那篇著名的文章《Inversion of Control Containers and the Dependency Injection pattern》中将具体依赖注入划分为三种形式,即构造器注入、属性(设置)注入和接口注入,习惯将其划分为一种(类型)匹配和三种注入:
- 类型匹配(Type Matching):虽然我们通过接口(或者抽象类)来进行服务调用,但是服务本身还是实现在某个具体的服务类型中,这就需要某个类型注册机制来解决服务接口和服务类型之间的匹配关系;
- 构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;
- 属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;
- 方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。
这里讲解.NET的Microsoft.Practices.Unity、Microsoft.Practices.Unity.Configuration和System.ComponentModel.Composition。
1、 首先讲解Microsoft.Practices.Unity讲解,这里不区分是哪一种注入,只为实现功能。
public interface IKiss { string kiss(); } public class Boy : IKiss { public string kiss() { return "boy kissing"; } } public class Lisy : IKiss { public string kiss() { return "Lisy kissing"; } }
//通过直接创建的方式,在main中写 //创建容器 IUnityContainer container = new UnityContainer(); //注册映射 container.RegisterType<IKiss, Boy>(); //得到Boy的实例 var boy = container.Resolve<IKiss>(); Title=boy.kiss();
通过配置调用
///通过配置 IUnityContainer container = new UnityContainer(); UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection; configuration.Configure(container, "defaultContainer"); var Lisy = container.Resolve<IKiss>("Lisy"); Title = Lisy.kiss();
<configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity> <containers> <container name="defaultContainer"> <register type="TestDependency.IKiss,TestDependency" name="Boy" mapTo="TestDependency.Boy,TestDependency" /> <register type="TestDependency.IKiss,TestDependency" name="Lisy" mapTo="TestDependency.Lisy,TestDependency" /> </container> </containers> </unity>
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity> <containers> <container name="defaultContainer"> <register type="ConsoleApplication1.IA,ConsoleApplication1" mapTo="ConsoleApplication1.A,ConsoleApplication1" /> <register type="ConsoleApplication1.IB,ConsoleApplication1" mapTo="ConsoleApplication1.B,ConsoleApplication1" /> <register type="ConsoleApplication1.IC,ConsoleApplication1" mapTo="ConsoleApplication1.C,ConsoleApplication1" /> <register type="ConsoleApplication1.ID,ConsoleApplication1" mapTo="ConsoleApplication1.D,ConsoleApplication1" /> </container> </containers> </unity> </configuration>
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.Configuration; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { UnityContainer container = new UnityContainer(); UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection; configuration.Configure(container, "defaultContainer"); A a = container.Resolve<IA>() as A; if (null != a) { Console.WriteLine("a.B==null?{0}", a.B == null ? "Yes" : "No"); Console.WriteLine("a.C==null?{0}", a.C == null ? "Yes" : "No"); Console.WriteLine("a.D==null?{0}", a.D == null ? "Yes" : "No"); } Console.WriteLine(a.kiss()); //Lily lily = new Lily(boy); //lily.kiss(); Console.Read(); } } public interface IKiss { string kiss(); } public class Lily : IKiss { public IKiss boy; public Lily(IKiss boy) { this.boy = boy; } public string kiss() { return "lily kissing"; } } public class Boy : IKiss { public string kiss() { return "boy kissing"; } } public interface IA { string kiss(); } public interface IB { string kiss(); } public interface IC { string kiss();} public interface ID { string kiss();} public class A : IA { public IB B { get; set; } //构造器注入 public A(IB b) { this.B = b; Console.WriteLine("属性注入"); } //属性注入,这种笔构造器和方法注方便 [Dependency] public IC C { get; set; } //方法注入 public ID D { get; set; } [InjectionMethod] public void Initalize(ID d) { this.D = d; Console.WriteLine("构造器注入"); } public string kiss() { return "IA kissing "+B.kiss() +" "+C.kiss() +" "+D.kiss(); } } public class B : IB { public string kiss() { return "IB kissing"; } } public class C : IC { public string kiss() { return "IC kissing"; } } public class D : ID { public string kiss() { return "ID kissing"; } } }
2.第二种System.ComponentModel.Composition
public interface ITestService { string GetUserName(); } [Export(typeof(ITestService))] public class TestService : ITestService { public string GetUserName() { return "Hello World!"; } }
执行
[Import] public ITestService TestService { get; set; } protected void Page_Load(object sender, EventArgs e) { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); CompositionContainer container = new CompositionContainer(catalog); container.ComposeParts(this); Title = TestService.GetUserName(); }