.Net動態代理Castle系列(一)---初步認識


  自己接觸NHibernate,Spring.Net,Moq這些框架有一段時間了,覺得很多很Cool的功能在這些框架中的實現都建立在動態代理這個技術之上,特來跟大家分享一下,希望大家一起討論,一起進步,我的計划是這個系列將會有四篇文章:

  1..Net動態代理Castle系列(一)---初步認識 

  2..Net動態代理Castle系列(二)---ORM中延遲加載及實現

  3..Net動態代理Castle系列(三)---在Mock框架中的運用及實現

  4..Net動態代理Castle系列 (四)---在AOP中的運用及實現 

  今天先開始對動態代理有個初步的認識,並通過實例來讓大家能認識到Castle,並能使用Castle.

  什么是動態代理?想很好的了解動態代理,就需先來了解代理的概念,代理(Proxy)這個概念在現實生活中無處不在,比如房屋中介,它就是一個代理對象,能代理行駛房東(可以理解為Target)的權力,除此之外中介可以對房東的權力添加一些附加值,攔截房東的一些行為,如收取中介費。

  在設計模式中,有一種模式叫做代理模式,在GOF中這樣寫道:

  為其他對象提供一種代理以控制對這個對象的訪問。

  接下來,為了方便大家了解,我還是以代碼的形式來描述下中介與房東之間的故事。

  首先,先來抽象房東的接口

   public interface ILandlordible
    {
        void RentHouse();
    }

 

  建立一個房東的類並實現接口

    public class Landlord:ILandlordible
    {
        public void RentHouse()
        {
            Console.WriteLine("房東收取租金!");
        }
    }

  房東委托中介出租,現在建立一個中介的類:

    public class Intermediary:ILandlordible
    {
        private ILandlordible landlor;

        public Intermediary(ILandlordible landlor)
        {
            this.landlor = landlor;
        }

        private void CollectIntermediaryFees()
        {
            Console.WriteLine("中介收取服務費!");
        }
        
        public void RentHouse()
        {
            landlor.RentHouse();
            CollectIntermediaryFees();
        }
    }

  可以看到關於Intermediary的實現

  1.首先實現一個ILandlordible的接口,因為它將具有房東出租房屋的權力

  2.然后類中保存着ILandlordible的引用,因為它將被委托房東的行為

  3.在RentHouse方法中,中介首先執行房東的行為,然后收取中介費。

  最后,中介跟房東之間的故事就要上演啦:

    class RentHouseStoryGeneralProxyVersion
    {
        static void Main(string[] args)
        {
            Console.WriteLine("房東委托中介幫其出租房屋!");
            ILandlordible landlord = new Intermediary(new Landlord());
            Console.WriteLine("中介成功出租房屋");
            landlord.RentHouse();
        }
    }

執行結果:    

  完成上面這個例子之后,想必大家對代理模式有了一定的了解,接下來將來講解動態代理模式。

  動態代理,我的理解是在運行時動態地產生代理類,進而產生代理對象。結合中介這個例子,即中介類可以動態的產生,沒有必要去自己實現它。

  要動態的產生一個或者攔截它的行為,在.NET平台下:

  1..NET Remoting中可以利用后門進行攔截,但是必須顯示的繼承ContextBoundObject類,我覺得這個方案不是很好,因為往往具有分類學區分的類之前的關系才會采用繼承,而且會受到單繼承的限制。

  2.Emit對IL直接進行操作,這個也是辦法,但是我覺得過於復雜,而且沒有必要研究到那個深度,所以我也不是很推薦。

  3.在前面介紹的兩種方法之間,我選取了一個折中的難度的方法,Castle.Net 是一個開源項目,它有一個動態代理的庫能很好地解決.NET平台下動態代理的問題,也被很多流行的框架所采用,如NHibernate,Moq.

  我還是來個例子,將中介的例子改編成動態代理版本:

  首先根據代理,讓我們來簡單的了解下Castle中的ProxyGenerator這個類:

    public class ProxyGenerator
    {
        public ProxyGenerator();
        public ProxyGenerator(IProxyBuilder builder);
        public IProxyBuilder ProxyBuilder { get; }
        public T CreateClassProxy<T>(params IInterceptor[] interceptors);
    }

  這里我摘取了ProxyGenerator的一些片段,這個類可以從名字中很容易看出它可以為我們動態地產生代理,但是仔細思考一下代理一定要有目標,如中介代理房東,所以CreateClassProxy這個泛型的方法就是指定需要代理的目標,這樣就可以我某個特定的類產生代理。但是,僅僅指定目標是不夠的,如中介它除了執行房東的職責之外,中介這個代理對象還有自己額外的邏輯,如收取服務費用。所以CreateClassProxy提供了一個可變的參數IInterceptor數組。來看看IInterceptor接口

   public interface IInterceptor
    {
        void Intercept(IInvocation invocation);
    }

  當我在調用CreateClassProxy並傳入實現了IInterceptor的對象時,所有的方法都將被IInterceptor的Intercept方法所攔截,並且Interceptor的參數IInvocation攜帶了所調用方法的所有信息,這樣我們就可以對所調用的方法進行全面的攔截,為所欲為。

  那我們就開始動手完成我們動態代理版的中介與房東之間的故事吧:

  繼續沿用之前的ILandlordible接口,但對於Landlord(房東)類,由於需要對它產生一個代理類,原理是需要繼承於Landlord類,對源類的方法進行重載,利用多態性,利用接口調用到重載的方法,所以對源類進行修改:

    public class Landlord:ILandlordible
    {
        public virtual void RentHouse()
        {
            Console.WriteLine("房東收取租金!");
        } 
    }

  修改就是將源類的方法改為虛方法,看到這里,如果用過NHibernate的朋友,是否覺得有點似曾相似,這就是為什么NHibernate的所以實體屬性需要加上Virtual關鍵字,關於原因我將在下一篇文章中跟大家一起分享。

  至於Intermediary(中介)類將由動態代理產生,所以就將不再使用,現在問題的核心就在於怎么利用Castle實現代理類,並添加收取服務費的邏輯。

  首先建立一個攔截器實現IInterceptor接口

    public class IntermediaryIntercetor:IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            //執行房東的邏輯
            invocation.Proceed();
            CollectIntermediaryFees();
        }

        private void CollectIntermediaryFees()
        {
            Console.WriteLine("中介收取服務費!");
        }
    }

  有了這個攔截器就可以開始動態代理版的故事啦:

    class RentHouseStroyDynamicProxyVersion 
    {
        static void Main(string[] args)
        {
            Console.WriteLine("房東委托中介幫其出租房屋!");
            Landlord proxyLandlord = CreateLandlordProxy();
            Console.WriteLine("中介成功出租房屋");
            proxyLandlord.RentHouse();
        }

        private static Landlord CreateLandlordProxy()
        {
            ProxyGenerator proxyGenerator = new ProxyGenerator();
            Landlord proyLandlord = proxyGenerator.CreateClassProxy<Landlord>(new IntermediaryIntercetor());
            return proyLandlord;
        }
    }

執行結果:    

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM