.Net下面實現依賴注入的架構有很多,如Spring.Net等等。微軟也有自己的工具---Unity。作為企業庫的一部分,Unity實現依賴注入也成為學習企業庫比較重要的一環。微軟給出的說法是【它是一個輕量級的、可擴充的依賴注入容器】。
對Unity進階用法,我還不是很熟悉,一下就簡單說說它的初級用法,給初學者掃掃盲,高手就可以直接跳過了。如果我理解有誤,還希望大鳥們不理賜教。
首先介紹一下開發環境:Visio Studio2008 Team,SP1、企業庫版本5.0。
提到Unity,就不能不說UnityContainer。UnityContainer是Unity中最基礎的類,它是實現依賴注入的基礎。 這裡我只給出一種最基本的攔截方式------UnityContainer對象中RegisterType、Resolve實現。RegisterType從函數名上理解就是註冊類型之間的關係。Resolve:通過UnityContainer對象擷取註冊的對象。被攔截的對象需要實現IInterceptionBehavior介面。
總體上,實現攔截有兩個步驟:
1、註冊被攔截對象
2、擷取被攔截對象的執行個體。
當然,以上兩步都是通過UnityContainer來實現的。也可以通過配置的方式來實現。這裡先熟悉一下通過編程的方式來進行配置的應用,通過配置的方式實現,留待之後介紹建構函式注入、屬性、方法注入的時候再進行介紹。
先簡要介紹一下本節樣本中類、介面之間的關係。人員介面IPerson、學生類Student,Student實現IPerson。我們需要攔截Student類中實現的IPerson介面中的方法【一個為虛方法、一個為執行個體方法】並在攔截的所執行的目標方法執行進行一些輸出操作。實現攔截得到類ILogInterception、ILogInterception1,需要實現企業庫介面-----IInterceptionBehavior。代碼如下:
public interface IPerson { string Name { get; set; } int Age { get; set; } void Speek(); void Run(int speed); }public class Student : IPerson { public string Name { get; set; } public int Age { get; set; } public virtual void Speek() { Name = "tesetName"; Age = 29; Console.WriteLine("Person Speeks"); } public void Run(int speed) { Console.WriteLine(string.Format("Student Runs... at speed {0}", speed)); } }public class LogInterception : IInterceptionBehavior { private static readonly MethodInfo methodInfo = typeof(Student).GetMethod("Speek"); public IEnumerable<Type> GetRequiredInterfaces() { return new[] { typeof(IPerson) }; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("開始攔截"); if (input == null) { throw new Exception("參數不能為null"); } if (getNext == null) { throw new Exception("委託不能為null"); } if (input.MethodBase == methodInfo) { Console.WriteLine("開始執行目標方法"); return getNext()(input, getNext); } else { return input.CreateMethodReturn(null); } } public bool WillExecute { get { return true; } } } public class ILogInterception1 : IInterceptionBehavior { private static readonly MethodInfo methodInfo = typeof(IPerson).GetMethod("Run"); public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return new[] { typeof(IPerson) }; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("開始攔截"); if (input == null) { throw new Exception("參數不可為空"); } if (getNext == null) { throw new Exception("委託沒有被執行個體化"); } if (input.MethodBase == methodInfo) { Console.WriteLine("即將執行目標方法"); Console.WriteLine(string.Format("目標方法參數個數為:{0}",input.Arguments.Count)); if (input.Arguments.Count > 0) { Console.WriteLine(string.Format("實際參數為:{0}", input.Arguments[0])); } InvokeInterceptionBehaviorDelegate tempDelegate = getNext(); return tempDelegate(input, getNext); } else { return input.CreateMethodReturn(null); } } }
在攔截虛方法的使用代碼如下:
container.AddNewExtension<Interception>(); container.RegisterType<Student>( new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<LogInterception>(), new AdditionalInterface<IPerson>()); var studentInfo = container.Resolve<Student>(); studentInfo.Speek();
輸出如:
由以上輸出結果可知:studentInfo在調用Speek方法時,首先不是直接去調用Student類的Speed方法,而是執行了LogInterception類中的Invoke方法。在Invoke方法getNext()(input, getNext)中,才真正調用了Student類的Speed方法。這就是我們所說的攔截。
以上是對介面中的虛方法中的攔截方式。對執行個體方法的攔截方式和上述攔截又有所不同。執行個體方法的攔截方式如下:
container.AddNewExtension<Interception>(); container.RegisterType<IPerson,Student>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<ILogInterception1>() ); var student = container.Resolve<IPerson>(); student.Run(100);
輸出如:
注意:攔截虛方法和攔截執行個體方式的方式是不一樣的。如果用攔截執行個體的方式來攔截虛方法或者用攔截虛方法的方式來攔截執行個體方法,則不會有對我們需要進行攔截的方法進行攔截。
此外,一種寫法在我看攔截的時候有點費解,就是getNext()(input, getNext);因為在我們的編程習慣裡,什麼時候會有一個方法會有這種調用方式呢。?這裡就需要好好考慮考慮了。getNext只是一個簡單的方法簽名嗎。?實際上它是GetNextInterceptionBehaviorDelegate類型的。從其名字上看便可知它是一個委託類型,可是委託也沒有像這樣使用的。再看看GetNextInterceptionBehaviorDelegate的定義:
public delegate InvokeInterceptionBehaviorDelegate GetNextInterceptionBehaviorDelegate();
從GetNextInterceptionBehaviorDelegate的簽名便知道它的傳回值InvokeInterceptionBehaviorDelegate應該也是一種委託類型的,如果是這樣那也不足為怪了。驗證一下這個想法,看看InvokeInterceptionBehaviorDelegate的定義:
public delegate IMethodReturn InvokeInterceptionBehaviorDelegate(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext);
確實,它是一個需要IMethodInvocation、與GetNextInterceptionBehaviorDelegate類型的委託。