这是EnterLib PIAB的BUG吗?
在默認的情況下,EnterLib的PIAB采用基于TransparentProxy/RealProxy的機制實現(xiàn)對方法調(diào)用的攔截,進而實現(xiàn)了對橫切關(guān)注點(Crosscutting Concern)的動態(tài)注入。也正是其來截機制本身的局限,當(dāng)我們才用PIAB的方式進行對象的創(chuàng)建的時候,要求本創(chuàng)建對象的類型要么實現(xiàn)某一個接口,要么繼承MarshalByRefObject類型。但是當(dāng)我們讓抽象基類繼承自MarshalByRefObject就不行了,我個人覺得這是微軟需要改進的地方。
一、基于接口實現(xiàn)和對MarshalByRefObject直接繼承的編程
我們先來看看PIAB默認支持的編程方法。為此便于演示,我創(chuàng)建了一個自定義的CallHandler:FooCallHandler。在Invoke方法中,我在調(diào)用目標(biāo)方法前后在控制臺輸出相應(yīng)的文字,表明該CallHandler得以正常執(zhí)行。下面是FooCallHandler和它對應(yīng)的HandlerAttributed的定義:
1: public class FooCallHandler : ICallHandler 2: { 3: public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) 4: { 5: Console.WriteLine("PreOperation..."); 6: var methodReturn = getNext()(input, getNext); 7: Console.WriteLine("PostOperation..."); 8: return methodReturn; 9: } 10:? 11: public int Order { get; set; } 12: } 13:? 14: public class FooCallHandlerAttribute : HandlerAttribute 15: { 16: public override ICallHandler CreateHandler(IUnityContainer container) 17: { 18: return new FooCallHandler { Order = this.Order }; 19: } 20: }先來模擬以及接口實現(xiàn)的編程方式,為此我們定義了一個接口IFoo,實現(xiàn)該接口的類型Foo。IFoo和Foo定義在如下的代碼片斷中,上面創(chuàng)建的FooCallHandler通過自定義特性的方式應(yīng)用到類型Foo上面。在Main方法中,調(diào)用PolicyInjection的泛型方法Create,并指明接口和具體類型的方式來創(chuàng)建Foo對象。
1: class Program 2: { 3: static void Main() 4: { 5: var foo = PolicyInjection.Create<Foo, IFoo>(); 6: foo.DoSomething(); 7: } 8: } 9: public interface IFoo 10: { 11: void DoSomething(); 12: } 13: [FooCallHandler] 14: public class Foo : IFoo 15: { 16: public void DoSomething() 17: { 18: Console.WriteLine("Do something..."); 19: } 20: }從下面的輸出我們可以看出,應(yīng)用在類型Foo上面的FooCallHandler在目標(biāo)方法被調(diào)用之前先得到了執(zhí)行。
1: PreOperation... 2: Do something... 3: PostOperation...你也可以讓Foo直接繼承自MarshalByRefObject。如果你執(zhí)行下面的代碼,你依然可以得到與上面一樣的輸出結(jié)果:
1: class Program 2: { 3: static void Main() 4: { 5: var foo = PolicyInjection.Create<Foo>(); 6: foo.DoSomething(); 7: } 8: } 9: [FooCallHandler] 10: public class Foo : MarshalByRefObject 11: { 12: public void DoSomething() 13: { 14: Console.WriteLine("Do something..."); 15: } 16: }二、將接口變成抽象類
我們推薦面向抽象的編程方式,具體有兩種主要的表現(xiàn):基于接口編程和基于抽象類編程。現(xiàn)在,我們將接口IFoo換成抽象類FooBase,具體改變?nèi)缦滤尽?/p> 1: class Program 2: { 3: static void Main() 4: { 5: var foo = PolicyInjection.Create<Foo, FooBase>(); 6: foo.DoSomething(); 7: } 8: } 9:? 10: public abstract class FooBase 11: { 12: public abstract void DoSomething(); 13: } 14:? 15: [FooCallHandler] 16: public class Foo: FooBase 17: { 18: public override void DoSomething() 19: { 20: Console.WriteLine("Do something..."); 21: } 22: }
?
上面的程序運行后,會拋出如下圖所示的ResolutionFailedException異常。錯誤消息表明異常是應(yīng)該FooBase不能被實例化導(dǎo)致的——FooBase是抽象類。但是我們實例化的時具體類型Foo,FooBase能否實例化與此無關(guān)。
三、讓FooBase繼承MarshalByRefObject
上面我們說過,能被PIAB進行攔截的類型要么實現(xiàn)一個接口,要么繼承MarshalByReObject類。如果我們將FooBase繼承自MarshalByReObject,是否會避免上述異常的拋出呢?為此,我們對FooBase加上了這個基類。
1: public abstract class FooBase: MarshalByRefObject 2: { 3: public abstract void DoSomething(); 4: }運行我們的程序,會拋出和上面完全一樣的異常。
四、抽象類可以這樣用
經(jīng)過我的實驗,抽象類可以這樣用:將繼承自MarshalByRefObject的具體類作為抽象類的基類。按照這個原理,我們對上面的例子作了如下改動:將FooBase從抽象類換成具體類,將Foo變成抽象類(Foo依然繼承自FooBase),然后創(chuàng)建另一個繼承自Foo的具體類FooImpl。
1: class Program 2: { 3: static void Main() 4: { 5: var foo = PolicyInjection.Create<FooImpl, FooBase>(); 6: foo.DoSomething(); 7: } 8: } 9: public class FooBase: MarshalByRefObject 10: { 11: public virtual void DoSomething() 12: { 13: throw new NotImplementedException("This method must be implemented by subclasses"); 14: } 15: } 16: public abstract class Foo : FooBase { } 17: [FooCallHandler] 18: public class FooImpl : Foo 19: { 20: public override void DoSomething() 21: { 22: Console.WriteLine("Do something..."); 23: } 24: }作了如此修改后,運行我們的程序之后我們能夠得到正確的結(jié)果。不過,為了讓PIAB提供對抽象類的支持而多加上一個非抽象的基類,在設(shè)計上是很丑陋的,我個人是不能接受的。實際上,我覺得這是PIAB自身的一個BUG,或者是自身欠考慮的地方。因為在實現(xiàn)的可行性上沒有任何問題。我親自在我自己開發(fā)的基于TransparentProxy/RealProxy的AOP框架(《自己動手創(chuàng)建迷你版AOP框架》)中經(jīng)過驗證,讓抽象類繼承MarshalByRefObject,并基于該抽象類創(chuàng)建一個可被攔截的TransparentProxy對象是可以實現(xiàn)的。
作者:Artech出處:http://artech.cnblogs.com/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
總結(jié)
以上是生活随笔為你收集整理的这是EnterLib PIAB的BUG吗?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 房贷不还会有什么后果
- 下一篇: Java 学习网站汇总贴