Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入(Constructor Injection)、属性注入(Property Injection),以及方法调用注入(Method Call Injection).
假设我们有下面的场景代码,在代码里面有一个很简单的customer对象,customer 对象有个save 方法, 这个方法通过调用ICustomerDataAccess.Save将数据持久到数据库中, 在列子中我们实现了dataaccess的sql版本和mysql版本,也就是说我们这个customer对象,可以支持持久化到sql server 或 mysql.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity; namespace UnitySample { public interface ICustomerDataAccess { void Save(Customer c); } public class CustomerSqlDataAccess : ICustomerDataAccess { public void Save(Customer c) { Console.Write("{2}, save data id:{0},name{1}",c.Id,c.Name,this.GetType().ToString()); } } public class CustomerMysqlDataAccess : ICustomerDataAccess { public void Save(Customer c) { Console.Write("{2}, save data id:{0},name{1}", c.Id, c.Name, this.GetType().ToString()); } } public class Customer { public ICustomerDataAccess CustomerDataAccess { get; set; } public string Id { get; set; } public string Name { get; set; } public void Save() { CustomerDataAccess.Save(this); } } class Program { static void Main(string[] args) { } } }
传统做法可能是在配置文件中填几个一个变量 dbType = sql or my sql. 然后在customer 对象中根据设定的db type 来实力化不同的dataaccess.
代码可能会是下面这个样子,这样的话,customer 对象实际上依赖于CustomerSqlDataAccess 和 CustomerSqlDataAccess 的,而且,未来比如要新增加其他数据库的支持,则必须修改customer 对象的源代码。
public Customer() { if (DbType = "sql") { CustomerDataAccess = new CustomerSqlDataAccess(); } else { CustomerDataAccess = new CustomerSqlDataAccess(); } }
下面我们使用unity 来解除customer 对象对 CustomerSqlDataAccess 和 CustomerSqlDataAccess 的依赖。
一、 属性注入(Property Injection)
1. 配置unity
为了以后调用方便,我这里建立了一个静态方法,然后注入了两个dataaccess。
public class UnitySetup { public static void Config() { var container = new UnityContainer(); container.RegisterType<ICustomerDataAccess, CustomerSqlDataAccess>(); container.RegisterType<ICustomerDataAccess, CustomerSqlDataAccess>("mysql"); } }
然后我们需要在Main函数中调用这个方法配置unity containter.
static void Main(string[] args) { UnitySetup.Config(); }
2. 标记属性注入
这步很简单,直接在customer 类中的ICustomerDataAccess 定义上面添加[Dependency]标注即可。
[Dependency] public ICustomerDataAccess CustomerDataAccess { get; set; }
3. 通过resove 获取对象
var container = new UnityContainer(); UnitySetup.Config(container); var sqlCustomer = container.Resolve<ICustomerDataAccess>(); var mysqlCustomer = container.Resolve<ICustomerDataAccess>("mysql");
上面的代码就分别获取了CustomerSqlDataAccess 实例和CustomerSqlDataAccess实例
二 、构造器注入(Constructor Injection)
1. 配置unity
unityContainer.RegisterType<Customer>( new InjectionConstructor(new ResolvedParameter<ICustomerDataAccess>())); unityContainer.RegisterType<Customer>("mysqlCustomer", new InjectionConstructor(new ResolvedParameter<ICustomerDataAccess>("mysql")));
添加两行注册customer 对想到container.
2. 获取
var sqlCustomer = container.Resolve<Customer>(); var myqlCustomer = container.Resolve<Customer>("mysqlCustomer");
完整代码如下
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity; namespace UnitySample { public interface ICustomerDataAccess { void Save(Customer c); } public class CustomerSqlDataAccess : ICustomerDataAccess { public void Save(Customer c) { Console.WriteLine("{2}, save data id:{0},name{1}",c.Id,c.Name,this.GetType().ToString()); } } public class CustomerMysqlDataAccess : ICustomerDataAccess { public void Save(Customer c) { Console.WriteLine("{2}, save data id:{0},name{1}", c.Id, c.Name, this.GetType().ToString()); } } public class UnitySetup { public static void Config(IUnityContainer unityContainer) { unityContainer.RegisterType<ICustomerDataAccess, CustomerSqlDataAccess>(); unityContainer.RegisterType<ICustomerDataAccess, CustomerMysqlDataAccess>("mysql"); unityContainer.RegisterType<Customer>( new InjectionConstructor(new ResolvedParameter<ICustomerDataAccess>())); unityContainer.RegisterType<Customer>("mysqlCustomer", new InjectionConstructor(new ResolvedParameter<ICustomerDataAccess>("mysql"))); } } public class Customer { private ICustomerDataAccess CustomerDataAccess { get; set;} public string Id { get; set; } public string Name { get; set; } public Customer(ICustomerDataAccess customerDataAccess) { CustomerDataAccess = customerDataAccess; } public void Save() { CustomerDataAccess.Save(this); } } class Program { static void Main(string[] args) { var container = new UnityContainer(); UnitySetup.Config(container); var sqlCustomer = container.Resolve<Customer>(); var myqlCustomer = container.Resolve<Customer>("mysqlCustomer"); sqlCustomer.Save(); myqlCustomer.Save(); Console.ReadKey(); } } }
三 、 方法调用注入(Method Call Injection)
方法调用注入和输入注入有点类似,只需要在调用的方法上面添加[InjectionMethod] 标注即可
1. 配置unity
unityContainer.RegisterType<Customer>("mysqlCustomer", new InjectionMethod("SetDataAccess", new ResolvedParameter<ICustomerDataAccess>("mysql")));
2. 获取
var sqlCustomer = container.Resolve<Customer>(); var myqlCustomer = container.Resolve<Customer>("mysqlCustomer");
完成后的代码如下
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity; namespace UnitySample { public interface ICustomerDataAccess { void Save(Customer c); } public class CustomerSqlDataAccess : ICustomerDataAccess { public void Save(Customer c) { Console.WriteLine("{2}, save data id:{0},name{1}",c.Id,c.Name,this.GetType().ToString()); } } public class CustomerMysqlDataAccess : ICustomerDataAccess { public void Save(Customer c) { Console.WriteLine("{2}, save data id:{0},name{1}", c.Id, c.Name, this.GetType().ToString()); } } public class UnitySetup { public static void Config(IUnityContainer unityContainer) { unityContainer.RegisterType<ICustomerDataAccess, CustomerSqlDataAccess>(); unityContainer.RegisterType<ICustomerDataAccess, CustomerMysqlDataAccess>("mysql"); unityContainer.RegisterType<Customer>("mysqlCustomer", new InjectionMethod("SetDataAccess", new ResolvedParameter<ICustomerDataAccess>("mysql"))); } } public class Customer { private ICustomerDataAccess CustomerDataAccess { get; set;} public string Id { get; set; } public string Name { get; set; } public void Save() { CustomerDataAccess.Save(this); } [InjectionMethod] public void SetDataAccess(ICustomerDataAccess dataAccess) { CustomerDataAccess = dataAccess; } } class Program { static void Main(string[] args) { var container = new UnityContainer(); UnitySetup.Config(container); var sqlCustomer = container.Resolve<Customer>(); var mysqlCustomer = container.Resolve<Customer>("mysqlCustomer"); sqlCustomer.Save(); mysqlCustomer.Save(); Console.ReadKey(); } } }
好了,通过使用unity 依赖注入,customer 对象不再依赖具体的CustomerSqlDataAccess 和 CustomerMysqlDataAccess., 只依赖于接口ICustomerDataAccess。
上面就是unity 的基本用法介绍。