読者です 読者をやめる 読者になる 読者になる

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

もうちょっとDynamic Proxyの原理を理解しようとしてみる。あるいはMSDN探検隊。

MSDNはお友達♪

ということで、もうちょっと昨日のDynamic Proxyの原理を理解しようとしてみます。
あ、これはチュートリアルとかじゃなくて、本当にわからないものをなんだかなぁと考えてるだけです。一緒にMSDNの森をフラフラしましょうぜ。

まず一番のポイントになるのはメソッドを注入するクラスに付けられた属性の正体ですねぇ。

	[AttributeUsage(AttributeTargets.Class)]
	public class InterceptionAttribute : ContextAttribute
	{
		public InterceptionAttribute() : base("Interception") { }
		public override void GetPropertiesForNewContext(IConstructionCallMessage ccm)
		{
	    		ccm.ContextProperties.Add(new InterceptionProperty());
		}
	}

基底クラスContextAttributeのMSDNの記述はいかにもそっけなく

IContextAttribute インターフェイスと IContextProperty インターフェイスの既定の実装を提供します。

ふぅん・・・。じゃあIContextAttributeはというと・・・

IContextAttribute クラスは、すべてのコンテキスト属性から公開されます。 属性は、コンテキストに存在するプロパティに影響し、そのコンテキストで作成されるオブジェクトに特定のポリシーを適用します。

おぉ、これっぽいですね。そいじゃオーバーライドしているGetPropertiesForNewContextメソッドを見てみましょうか。

GetPropertiesForNewContext メソッドは、IConstructionCallMessage インターフェイスの ContextProperties プロパティ リストに直接コンテキスト プロパティを追加できます。 ContextAttribute クラスの既定の実装では、これをコンテキスト プロパティ リストに追加します。 コンテキスト属性によって GetPropertiesForNewContext をオーバーライドできるため、独自の動作を実装できます。 たとえば、コンテキスト プロパティを実装する新しいクラスをリストに追加できます。

・・・なんか出口が見えない迷路ですが頑張りましょうか。えーっと、コンテクストプロパティリストに追加されると一体どうなるんでしょうかね。ContextPropertiesは一体何を・・・?

通常、新しいオブジェクトのコンテキストは、クラスのメタデータ属性に基づいて選択されます。 コンテキスト選択機構は、静的コンテキスト プロパティとも呼ばれるカスタム属性に拡張できます。これはクラス メタデータにコンパイルされます。 オブジェクトをリモートからアクティブにする場合、ContextProperties は構築呼び出しメッセージのさまざまな属性が提供したプロパティの一覧を格納します。 これらのプロパティは、サーバー オブジェクトをアクティブにするコンテキストを作成するために使用します。

もうやめていいですか?(´・ω・`)
なんだよ、さっきからContext、Contextばっか言いやがって。。。そもそもサーバーオブジェクトをアクティブにするとかそんなもの設定した覚えは。。。あ?

ContextBoundObjectを継承したクラスは、ContextAttribute基底クラスを通じてIConceptPropertyオブジェクトを付加する事ができる。この仕組を使い、メソッドを引ったくりたいクラスに任意のConceptPropertyを注入する。

なるほろ、これか。ContextBoundObjectっていうのは。。。

コンテキスト内にあり、そのコンテキストの規則に拘束されているオブジェクトをコンテキスト拘束オブジェクトと呼びます。 コンテキストとは、オブジェクトのコレクションが存在する環境を定義する一連のプロパティや使用規則のことです。 これらの規則は、オブジェクトがコンテキストに入るとき、またはコンテキストを離れるときに強制的に適用されます。 コンテキストに拘束されていないオブジェクトは、非拘束オブジェクトと呼びます。

コンテキストは、オブジェクトがアクティブ化されるときに作成されます。 新しいオブジェクトは、既存のコンテキスト内、または型のメタデータに含まれている属性を使用して作成された新規コンテキスト内に配置されます。 コンテキスト バインド クラスは、使用規則を提供する ContextAttribute でマークされています。 追加できるコンテキスト プロパティには、同期やトランザクションに関するポリシーなどがあります。

つまり、リモートオブジェクトとかそんなこと関係なく、ContextBoundObjectはContextAttribute属性で注入されたContext上で実行される、ということなんすね。なるほど。

・・・だからContext上で実行されるってのはどういうことなんだよっ!!

めげずに読み進みましょう。
実際に注入されたContextはこんなんでした。

public class InterceptionProperty : IContextProperty, IContributeObjectSink
    {
    
    	#region IContextProperty Members

	    public void Freeze(Context newContext)
	    {
	
	    }
	
	    public bool IsNewContextOK(Context newCtx)
	    {
	        return true;
	    }
	
	    public string Name
	    {
	        get { return "InterceptionProperty"; }
	    }
	
	    #endregion
	
	    #region IContributeObjectSink Members
	
	    public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
	    {
	        return new InterceptionMainAspect(nextSink);
	    }
	
	    #endregion
	}

ポイントはIContributeObjectSinkインターフェイスに有りそうです。こいつは・・・

リモート処理呼び出しのサーバー エンドの、オブジェクト固有の傍受シンクを提供します。
IContributeObjectSink インターフェイスは、リモート処理呼び出しのサーバー エンドの、オブジェクト固有の傍受シンクを提供する Context クラスのコンテキスト プロパティによって実装されます。

サーバー オブジェクト チェーンは、IContributeObjectSink を実装するサーバー オブジェクトのコンテキストのコンテキスト プロパティで構成されます。 [] は、そのようなプロパティの例です。つまり、メッセージ シンクは、呼び出しが到達した後にオブジェクトをアクティブにし、その後、メッセージをオブジェクトに渡します。

Contextの中にIContributeObjectSinkの実装が入っていれば勝手に呼び出されるっぽい雰囲気ですね、これは。なるほど、だいぶ全貌がつかめてきました。
ちなみにシンクは”sink”で、「受信装置」のこと。もう一息っぽいですね。唯一のメソッド、GetObjectSinkは・・・

指定されたサーバー オブジェクトのメッセージ シンクを指定されたシンク チェーンの前につなげます。

「指定されたサーバーオブジェクトのメッセージシンク」というのが、属性を付加されたメソッドの呼び出し口にあたるということですね。うん、ちょっと納得。

まとめると、

  1. ContextBoundObjectは(サーバー越しの呼び出しとかじゃなくても)問答無用にContextに結び付けられるオブジェクトである。
  2. 結びつけるContextはContextAttributeを通じて渡すことができる。ここでは、ContextAttributeを継承したカスタム属性を使ってオーバーライドし、任意のContextを設定してる。
  3. Contextの全貌はとりあえず不明だけれど、IContributeObjectSinkが実装されているContextがContextPropertiesに設定されると、オブジェクト生成時にちゃんと呼び出して、メッセージの受信の前にフィルタをかけることができる。

うん、ちょっと分かった気分。