我們使用動態代理,主要是因為動態代理擁有這樣的能力--使得某個類型a在運行的時候能轉化為一個指定的接口i,即使這個類型a在定義的時候并沒有從這個指定的接口i繼承。這句話是什么意思了?還是回到當泛型的參數類型是動態的... 一文中的那個例子,在例子中,list<>并沒有從isimplelist繼承,但是從表面看來,在運行的時候,我們通過動態代理可以以isimplelist接口來“引用”list<>類型的對象。
動態代理是在運行時在內存中構建的一種類型,該類型實現了接口i,但是它將所有的方法調用都轉發給類型a。
注意,上面我使用了“方法”調用的轉發,由于,事件、屬性都是方法的變體,所以,對接口中定義的所有元素的call都可以被動態代理轉發。那么,接口(i)中的方法與被代理者(target)的方法如何匹配起來了?通常的方法是,進行“同名”匹配,比如isimplelist接口的add方法就自然匹配到list<>的add方法。對于復雜的需求,可以定義一個方法名映射表來匹配不同名的方法。
由于,動態代理擁有這種為類型(target)“換臉”的能力,所以,在很多場合可以使用它來優雅地解決一些以前難以處理的問題(通常,以前我們使用反射來解決這些麻煩),比如:
(1)“泛型參數類型是動態的”,使用動態代理解決這種問題不僅可以避免反射帶來的性能損失,而且還可以獲得強類型方法調用的好處。
(2)為一組類型“變臉”。比如,textbox、richtextbox、listview等windows控件都有clear方法,但是它們都沒有實現一個統一的接口(比如,該接口中定義了clear方法),所以當我要清空某個groupbox中所有控件的內容時,無法用一種統一的方式調用,你不能這樣做:
| 以下為引用的內容: foreach (control control in this.groupbox1.controls) { control.clear(); //control不存在clear方法,編譯報錯 } |
但是有了動態代理之后,我們就可以為這些控件定義一個new face:
| 以下為引用的內容: public interface inewface |
然后優雅地這樣調用:
| 以下為引用的內容: foreach (control control in this.groupbox1.controls) |
你可以繼續挖掘使用動態代理的其它場合,發揮你的想象力,來展現動態代理的威力。
關于esbasic中的 dynamictypeemitter 實現,有一點缺憾,那就是暫時還不支持“泛型方法”的調用轉發,我還不知道如何使用emit發射對動態類型參數的泛型方法的調用,有知道的朋友請指導下。
新聞熱點
疑難解答