[WF 4 (6)] アクティビティコンテキスト (context) と変数 (Variable) の意義

環境 : Visual Studio 2010 Beta 2 (.NET Framework 4)

WF 4

  1. そのアイデアとベースクラスの変更
  2. コードいらずのワークフロー (入門)
  3. ワークフローのコードと XAML の内部
  4. フローチャート (FlowCharts)
  5. アクティビティ (基礎)
  6. アクティビティコンテキスト (context) と変数 (Variable) の意義
  7. アクティビティにおけるさまざまな実行管理
  8. アクティビティのデリゲート
  9. アクティビティの非同期実行
  10. アクティビティデザイナー
  11. ブックマーク
  12. Workflow Extensions と 永続化、トラッキング
  13. デザイナーリホスティングとカスタムアプリケーション

こんにちは。

ここまで (前回のサンプルでも)、何の説明もなく Variable だの、Argument (InArgument / OutArgument) だのといった変数を使ってきました。
今回は、この意義を改めて理解しておきましょう。

そのためには、まずアクティビティコンテキスト (Activity Execution Context, AEC) について理解しておく必要があります。
この「アクティビティコンテキスト」の概念は従来の WF にもあり、以前 もこのメカニズムについては説明したのですが、ここで改めて、WF 4 を例に解説しておきましょう。(大事な概念です)

例えば、以下の通りアクティビティを実装してみます。

public sealed class Activity1 : NativeActivity
{
    public string test1 = "bbb";

    protected override void Execute(NativeActivityContext context)
    {
        test1 += "b";
        Console.WriteLine(test1);
    }
}

このアクティビティを下図の通り ForEach アクティビティで使用したと仮定します。(今回は、下図の item の変数はいっさい使用していません。ただ 5 回ループする、というだけなので、While でも構いません。。。)

この出力結果は以下の通りになります。

bbbb

bbbbb

bbbbbb

bbbbbbb

bbbbbbbb

皆さんにとって、この結果は期待された結果でしょうか ? 中には、「これで良いじゃん !」 という方も居るかもしれませんが、通常、プログラマーの方の感性だと、「for 文の中で定義されたローカル変数は、そのスコープ内で初期化されるので、前の値を引きずらないはず !」と思われるでしょう。

WF では、上記の ForEach の中の Activity1 のように、ある 1 つのアクティビティが複製される場合、その複製は「アクティビティ コンテキスト」と呼ばれる WF 独自の概念によって複製されています。
従来の WF では、この「アクティビティ コンテキスト」という概念を理解してコードを記載していないと、しばしばこの落とし穴にはまり、期待されない結果を招いていました。WF 4では、こうした “WF 独自のメカニズム” といった点をできるだけ意識せずにコーディングできるように、さまざまな仕組みが提供されています。その 1 つが、今まで見てきた Variable や、Argument などになります。

例えば、上記の Activity1 を以下の通り書き換えてみましょう。(以下の CacheMetadata メソッドについてはあとで説明しますので、まずは無視してください。)

public sealed class Activity1 : NativeActivity
{
    private Variable<string> test1 = new Variable<string>("test1", "bbb");

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        metadata.AddImplementationVariable(this.test1);
    }

    protected override void Execute(NativeActivityContext context)
    {
        test1.Set(context, test1.Get(context) + "b");
        Console.WriteLine(test1.Get(context));
    }
}

このように Variable を使った変数だと、コンテキストを認識して管理されるため、出力結果は、

bbbb

bbbb

bbbb

bbbb

bbbb

となります。これで、期待通りになったわけです。

上記の CacheMetadata メソッドは、こうした管理下におかれる変数やアクティビティなどを登録するためのオーバーライドメソッドです。
前回 ご紹介した InArgument / OutArgument を使ったサンプルコードも同様で、この (Argument の) 宣言により、コンテキストで管理された引数となり、CacheMetadata で登録をおこなう必要があります。

[注意 !] なお、前回のサンプルを見ていただくとわかる通り、CacheMetadata メソッドは使っていませんが、実は、InArgument / OutArgument については、ベースクラスの CacheMetadata の中でこうした処理がおこなわれています。このため、CacheMetadata をオーバーライドした場合には、やはり Argument についても AddImplementationArgument をおこなうか、base.CacheMetadata を呼び出す必要があります。

今回、例を簡単にするため、「アクティビティコンテキスト」を上記のような「初期化」の観点だけでしか説明しませんでしたが、アクティビティコンテキストは、この他にも、親子関係の管理 (親のアクティビティコンテキストで宣言された変数は、子でも使用できます)、スレッディングにおける TLS のメカニズムなど、ワークフローの実装に欠かせないさまざまな管理をおこなっています。

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s