DynamicMessageSink

最後に残ったこいつを試さずに終わることはできない。
こいつを試すのは他の4つの Sink と違ってちょっと面倒だ。
まず、何が違うかというと IContextProperty の実装クラスで IDynamicProperty を実装し、IContributeDynamicMessageSink を実装する。
最初から1つのインターフェスでいいやん、とか突っ込んでみたくもなる。
その上で、利用するコンテキストかオブジェクトを指定して Context.RegisterDynamicProperty を呼び出してやらないと登録されないのだが、コンテキスト毎、オブジェクト毎に登録ができると考えれば、実は便利かもしれない?
さて、こいつは IMessageSink とは異なり、メッセージ交換の開始と終了で別々のメソッドを呼び出される。それだけ考えるとログ記録には結構もってこいのヤツともいえる。
問題はいつ呼び出されるか、なのだが……。

  1. ContextB.EnvoySink
  2. ContextA.ClientContextSink
  3. ContextA.ProcessMessageStart(コンテキストに対する登録時)
  4. context switch(CurrentContextが入れ替わる)
  5. ContextB.ProcessMessageStart(コンテキストに対する登録時)
  6. ContextB.ServerContextSink
  7. ContextB.ObjectContextSink
  8. ContextB.ProcessMessageStart(オブジェクトに対する登録時)
  9. context switch(CurrentContextが入れ替わる)
  10. ContextB.ProcessMessageFinish(コンテキストに対する登録時)

といったかんじの記録が手に入る。
呼び出し元を意識した記述に直すと、

  ContextB.EnvoySink.ProcessMessage()
  {
   ContextA.ClientContextSink()
  }

  ContextA.ClientContextSink()
  {
    if RegisterForContext 
      ContextA.ProcessMessageStart();

    ContextSwitch();

    if RegisterForContext
      ContextA.ProcessMessageFinish();
  }

  ContextSwitch()
  {
    ContextB.ServerContextSink();
  }

  ContextB.ServerContextSink()
  {
    if RegisterForContext
      ContextB.ProcessMessageStart();

    ContextB.ObjectContextSink();
  }

  ContextB.ObjectContextSink()
  {
    if RegisterForObject
      ContextB.ProcessMessageStart();
  }

といった感じになっているので、扱い方次第では便利なタイミングと言えるかもしれない。
ProcessMessageFinish() が ProcessMessageStart() と1対1になっていないところも注意が必要だろう。