微軟企業庫Unity學習筆記(二)
接下來介紹一下依賴注入的方式:
- 構造函數注入
- 屬性注入
- 方法注入

一、 構造函數注入
我們將介紹單構造函數和多構造函數注入
1) 單構造函數使用自動注入
- 單構造函數自動注入,這里我們使用一個簡單的例子具體類MyObject依賴于具體類MyDependentClass。
////具體類型的依賴關系
public class MyOjbect
{
private string description;
public string Description
{
get { return description; }
set { description = value; }
}
public MyOjbect(MyDependentClass myDependent)
{
this.Description = myDependent.Description;
}
}
////注入依賴
MyOjbect objlist = container.Resolve<MyOjbect>();
- 當然除了具體類型我們還可以使用接口或者基類類型作為參數注入依賴,這里我們定義一個接口和一個抽象類。
//// MyServiceBase是一個抽象類,然后objIMyService繼承于該抽象類
//// IMyService是一個接口,objMyService實現該接口
public class MyOjbect
{
private string description;
public string Description
{
get { return description; }
set { description = value; }
}
public MyOjbect(MyServiceBase objIMyService, IMyService objMyService)
{
////TODO:
}
}
////注冊抽象類和接口的映射關系
container.RegisterType<IMyService, MyServiceDependent>();
container.RegisterType<MyServiceBase, DataService>();
MyOjbect objlist = container.Resolve<MyOjbect>();
2) 多重載構造函數通過屬性指定注入構造函數
通過InjectionConstructor屬性指定要注入構造函數,和單構造函數功能一樣,但要注意一點是當有多重載構造函數,如果我們沒有使用屬性指定注入構造函數,Unity會根據構造函數參數最多的進行依賴注入,如果不存在唯一最多參數的構造函數(例如:有兩個或者兩個以上構造函數具有最多參數時候),Unity會拋出異常。
public class MyOjbect
{
private string description;
public string Description
{
get { return description; }
set { description = value; }
}
public MyOjbect(MyServiceBase objIMyService)
{
////
}
[InjectionConstructor]
public MyOjbect(MyServiceBase objIMyService, IMyService objMyService)
{
////
}
}
通過前面的介紹我們初步明白了Unity的作用就是給我們一個更方便實現類與類的解耦,假設在一般情況一個類依賴于其他類的時候,我們必須實例化該依賴類,然后把實例傳遞給我們要調用類,但有了Unity它幫我們實例了這些。OK接下來講一個具體例子。

/// <summary>
/// 父母類
/// </summary>
public class Parent
{
private readonly ChildA _classA;
private readonly ChildB _classB;
public Parent() { }
//指定依賴注入構造函數
[InjectionConstructor]
public Parent(ChildA chA, ChildB chB)
{
this._classA = chA;
this._classB = chB;
}
public override string ToString()
{
// 年長的父母依賴與孩子。
return string.Format("The elder depend on {0} and {1}.", this._classA.ToString(), this._classB.ToString());
}
}
/// <summary>
/// 孩子類
/// </summary>
public class ChildA : Parent
{
public override string ToString()
{
return "ChildA";
}
}
/// <summary>
/// 孩子類
/// </summary>
public class ChildB : Parent
{
public override string ToString()
{
return "ChildB";
}
}
class Program
{
static void Main(string[] args)
{
using (IUnityContainer container = new UnityContainer())
{
Parent objParent = container.Resolve<Parent>();
Console.WriteLine(objParent.ToString());
Console.ReadKey();
}
}
}

接下通過一個簡單的配置文件實例例子進一步說明,Unity是如何實現類與類之間的解耦的。
首先我們先定義一個Foo類,它依賴于一個接口ILogger,它有兩個實現分別是LoggerA和LoggerB,然后我們的Foo類要調用LoggerA。在一般情況下我們可以實例化一個LoggerA的實例,然后傳遞給Foo就OK了,這就是hard code給我們帶來了一個緊的耦合,如果要我們修改成調用LoggerB,那么我們可以再實例化一個LoggerB對象,眼前看來是可以這樣實現,但如果我們工程很大,這種做法是十分危險,當我們使用配置文件可以簡單實現,來講講簡單實現。

static void Main(string[] args)
{
using (IUnityContainer container = new UnityContainer())
{
////Parent objParent = container.Resolve<Parent>();
////Console.WriteLine(objParent.ToString());
////Console.ReadKey();
//獲取指定名稱的配置節
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
//獲取container名稱為CfgClass下的配置
section.Containers["CfgClass"].Configure(container);
Foo myFoo = container.Resolve<Foo>();
Console.WriteLine(myFoo.ToString());
Console.ReadKey();
}
}
App.config中的配置如下:
<configuration>
<configSections>
<!-- 每次都必須定義的開頭 -->
<section name ="unity" type ="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>
<!-- 使用unity的xsd -->
<!--<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">-->
<unity>
<!-- 聲明一種是用類型 -->
<typeAliases>
<typeAlias alias ="ILogger" type ="MSEnterpriseUnitity.ILogger, MSEnterpriseUnitity"/>
</typeAliases>
<containers>
<container name="CfgClass">
<!-- 設定該類型的映射關系 -->
<types>
<type type ="ILogger" mapTo="MSEnterpriseUnitity.LoggerA, MSEnterpriseUnitity" />
</types>
</container>
</containers>
</unity>
</configuration>
二、方法注入
當一個類的方法依賴于其他類的時候(例如構造函數參數依賴與其他類),在一般情況下通過實例化該被依賴類對象,然后將參數傳遞給我們依賴類的方法,如果使用方法注入可以避免實例化被依賴類對象,這里就僅僅需要在依賴方法中設置一個屬性InjectionMethod就OK了。
2.1方法依賴于具體類
首先我們定義兩個類MyTargetOjbect和OtherObject,然后定義在MyTargetOjbect中定義一個方法Initialize(OtherObject dep),該方法的參數依賴于OtherObject類。
/// <summary>
/// 依賴類包含一個Description和OutPut方法。
/// </summary>
public class OtherObject
{
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
public void OutPut()
{
Console.WriteLine(this.Description);
}
}
/// <summary>
/// 目標類的方法Initialize參數依賴于OtherObject類。
/// </summary>
public class MyTargetOjbect
{
public OtherObject dependentObject;
[InjectionMethod]
public void Initialize(OtherObject dep)
{
this.dependentObject = dep;
}
}
using (IUnityContainer container = new UnityContainer())
{
MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>();
myTargetObject.dependentObject.Description = "Injection successful.";
myTargetObject.dependentObject.OutPut();
}

2.2 方法依賴于接口或者基類
定義一個抽象類MyBaseClass,然后MyInheritBase繼承該抽象類,定義一個接口IMyInterface然后ImplementInterface實現該接口。
/// <summary>
/// 接口包含一個屬性和一個方法
/// </summary>
public interface IMyInterface
{
string Description
{
get;
set;
}
void OutPut();
}
/// <summary>
/// 實現IMyInterface的屬性和方法
/// </summary>
public class ImplementInterface : IMyInterface
{
private string _description;
#region IMyInterface 成員
public string Description
{
get
{
return _description;
}
set
{
_description = value;
}
}
public void OutPut()
{
Console.WriteLine(this.Description);
}
#endregion
}
/// <summary>
/// 一個抽象類包含一個屬性和一個方法
/// </summary>
public abstract class MyBaseClass
{
private string _description;
public virtual string Description
{
get { return _description; }
set { _description = value; }
}
public abstract void OutPut();
}
/// <summary>
/// 實現抽象類的抽象方法
/// </summary>
public class MyInheritBase : MyBaseClass
{
public override void OutPut()
{
Console.WriteLine(this.Description);
}
}
/// <summary>
/// 目標類的方法Initialize參數依賴于OtherObject類。
/// </summary>
public class MyTargetOjbect
{
public IMyInterface myInterface;
public MyBaseClass myBase;
[InjectionMethod]
public void Initialize(IMyInterface myInterface, MyBaseClass myBase)
{
this.myInterface = myInterface;
this.myBase = myBase;
}
}
////設置抽象類和接口的映射關系
container.RegisterType<MyBaseClass, MyInheritBase>();
container.RegisterType<IMyInterface, ImplementInterface>();
MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>();
myTargetObject.myInterface.Description = "Injection Successful.";
myTargetObject.myInterface.OutPut();
myTargetObject.myBase.Description = "Injection Successful.";
myTargetObject.myBase.OutPut();

三、屬性注入
當一個類的屬性依賴于其他類,一般情況初始化該屬性需要實例化該類型對象,然而我們可以使用Dependency屬性,指定屬性注入無限手動實例化類型對象。
3.1 具體類型屬性
public class MyObject
{
private SomeOtherObject _dependentObject;
[Dependency]
public SomeOtherObject DependentObject
{
get { return _dependentObject; }
set { _dependentObject = value; }
}
}
IUnityContainer uContainer = new UnityContainer();
MyObject myInstance = uContainer.Resolve<MyObject>();
// now access the property containing the dependency
SomeOtherObject depObj = myInstance.DependentObject;
3.2抽象類或接口屬性
public class MyObject
{
private IMyInterface _interfaceObj;
private MyBaseClass _baseObj;
[Dependency]
public IMyInterface InterfaceObject
{
get { return _interfaceObj; }
set { _interfaceObj = value; }
}
[Dependency]
public MyBaseClass BaseObject
{
get { return _baseObj; }
set { _baseObj = value; }
}
}
IUnityContainer uContainer = new UnityContainer()
.RegisterType<IMyInterface, FirstObject>()
.RegisterType<MyBaseClass, SecondObject>();
MyObject myInstance = uContainer.Resolve<MyObject>();
// now access the properties containing the dependencies
IMyInterface depObjA = myInstance.InterfaceObject;
MyBaseClass depObjB = myInstance.BaseObject;
3.3 給屬性注入命名
給屬性命名只需在Dependency(“name”)定義一個名字就OK了。
public class MyTargetOjbect
{
public IMyInterface myInterface;
public MyBaseClass myBase;
private IMyInterface _MyProperty1, _MyProperty2;
//命名屬性注入
[Dependency("Property2")]
public IMyInterface MyProperty2
{
get { return _MyProperty2; }
set { _MyProperty2 = value; }
}
//命名屬性注入
[Dependency("Property1")]
public IMyInterface MyProperty1
{
get { return _MyProperty1; }
set { _MyProperty1 = value; }
}
}
//調用Property1屬性注入
container.RegisterType<IMyInterface, ImplementInterface>("Property1");
//調用Property2屬性注入
container.RegisterType<IMyInterface, ImplementInterface2>("Property2");
MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>();
IMyInterface myProperty1 = myTargetObject.MyProperty1;
IMyInterface myProperty2 = myTargetObject.MyProperty2;
3.4 構造函數參數的屬性注入
構造函數參數依賴于其他類時候,我們可以考慮使用構造函數注入或者屬性注入
public class Foo
{
private ILogger _iLogger;
public Foo([Dependency] ILogger iLogger)
{
this._iLogger = iLogger;
}
public override string ToString()
{
return string.Format("Foo depends on {0}.", this._iLogger.ToString());
}
}
|
|
關于作者:[作者]:
JK_Rush從事.NET開發和熱衷于開源高性能系統設計,通過博文交流和分享經驗,歡迎轉載,請保留原文地址,謝謝。 |

本文主要介紹:
使用微軟的IoC框架,Untity來給我們的軟件設計解耦,注意介紹一下構造函數、屬性和方法注入技術。
浙公網安備 33010602011771號