Proxy の基礎

C# のプロキシ(代理/委任)の基礎です。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの作成

  1. Proxy を使って割り込みハンドラをフックします。
    まず最初にプログラムを作成して動かしてみて下さい。
    サンプルプログラムの全ソースコードです。
    /***********************************************/
    /*★ プロキシのサンプルプログラム    前田 稔 ★*/
    /***********************************************/
    namespace Handler
    {
        using System;
        using System.Runtime.Remoting;
        using System.Runtime.Remoting.Messaging;
        using System.Runtime.Remoting.Proxies;
    
        // 割り込みで実行されるメソッド(real proxy)
        public class Sample : MarshalByRefObject
        {
            public void Func()
            {
                Console.WriteLine("Func() が実行されました");
            }
        }
    
        // 透過プロキシ(transparent proxy)
        public class SampleProxy : RealProxy
        {
            private Sample sample;
    
            // 透過プロキシを返すファクトリメソッド
            static public Sample CreateSample()
            {
                Sample smpl = new Sample();
                SampleProxy proxy = new SampleProxy(smpl, typeof(Sample));
                return (Sample) proxy.GetTransparentProxy();
            }
    
            // base(type) で RealProxy のコンストラクタを呼び出す
            public SampleProxy( Sample smpl, Type type) : base(type)
            {
                sample = smpl;
            }
    
            // Invoke() をオーバライドして Method を呼び出す
            public override IMessage Invoke(IMessage imsg)
            {
                IMethodCallMessage call = (IMethodCallMessage) imsg;
                Console.WriteLine(call.MethodName + "を呼び出します");
                IMethodReturnMessage res = RemotingServices.ExecuteMessage(sample, call);
                return res;
            }
        }
    
        // 割り込みハンドラを起動する
        class SampleMain
        {
            [STAThread]
            static void Main(string[] args)
            {
                // 透過プロキシを生成する
                Sample sample = SampleProxy.CreateSample();
                // 透過プロキシから Func() を呼び出す
                sample.Func( );
                Console.ReadLine();
            }
        }
    }
    

プログラムの説明

  1. .NET Framework の割り込みでは、割り込み対象のクラスごとにプロキシオブジェクトと呼ばれるヘルパーオブジェクトを作成します。
    ターゲットのインスタンスを偽装する透過プロキシ(transparent proxy)と、割り込みハンドラを実装する実プロキシ(real proxy)です。
    real proxy が、割り込みで実際に実行されるクラスで、transparent proxy で割り込みと real proxy を関連付けます。
  2. 割り込みで実行される real proxy で、Func() が呼び出されるメソッドです。
    MarshalByRefObject を継承して下さい。
        public class Sample : MarshalByRefObject
        {
            public void Func()
            {
                Console.WriteLine("Func() が実行されました");
            }
        }
        
  3. 割り込みと real proxy を関連付ける transparent proxy です。
    RealProxy を継承して下さい。
        public class SampleProxy : RealProxy
        {
            private Sample sample;
        
  4. CreateSample() が Main() から呼ばれる透過プロキシを返すファクトリメソッドです。
    SampleProxy が生成される前に呼ばれるので、static で宣言しています。
    new で Sample Class を生成します。
    続いて生成した Sample をパラメータにして SampleProxy() を生成します。
    SampleProxy に今回呼び出すメソッド(Func)が間接的に設定されます。
        static public Sample CreateSample()
        {
            Sample smpl = new Sample();
            SampleProxy proxy = new SampleProxy(smpl, typeof(Sample));
            return (Sample) proxy.GetTransparentProxy();
        }
        
  5. SampleProxy Class のコンストラクタです。
    継承している RealProxy のコンストラクタを type を引数として呼び出します。
    パラメータで渡された Sample Class(smpl) を sample に保存します。
        public SampleProxy( Sample smpl, Type type) : base(type)
        {
            sample = smpl;
        }
        
  6. メソッド(Func)は Invoke() をオーバライドして呼び出します。
    IMessage は連携して動作する複数のメッセージシンク間で送信される通信データを格納するインターフェイスです。
    ExecuteMessage() でメソッドを呼び出して、実行結果をリターンします。
        public override IMessage Invoke(IMessage imsg)
        {
            IMethodCallMessage call = (IMethodCallMessage) imsg;
            Console.WriteLine(call.MethodName + "を呼び出します");
            IMethodReturnMessage res = RemotingServices.ExecuteMessage(sample, call);
            return res;
        }
        
  7. 割り込みハンドラを起動する Main() メソッドです。
    CreateSample() で透過プロキシを生成します。
    sample.Func() で透過プロキシを通じて Func() を呼び出します。
        class SampleMain
        {
            [STAThread]
            static void Main()
            {
                // 透過プロキシを生成する
                Sample sample = SampleProxy.CreateSample();
                // 透過プロキシから Func() を呼び出す
                sample.Func( );
                Console.ReadLine();
            }
        }
        

超初心者のプログラム入門(C# Frame Work)