2011年8月9日火曜日

WF をコードのみで利用する場合の注意

WF ではデザイナ上から利用するだけでなく、直接コードにて記述する事も可能です。その場合、各アクティビティに対して値を設定する場面で少し気を付ける必要があります。それはアクティビティコンテキストを用いた実行制御に関わる部分に、密接に関連があります。

単純にコードで記述する場合、以下のようなコードになることがあります。

   1: Dim wfVar As New Variable(Of Integer) With
   2:     {
   3:         .Name = "wfValue"
   4:     }
   5:  
   6: Dim seq As New Sequence
   7: seq.Variables.Add(wfVar)
   8:  
   9: Dim ass As New Assign(Of Integer) With
  10:     {
  11:         .To = wfVar,
  12:         .Value = (New Random).Next(1, 100)
  13:     }
  14: seq.Activities.Add(ass)
  15: Dim wrt As New WriteLine With
  16:     {
  17:         .Text = New InArgument(Of String)(Function(env) "生成された値は " + wfVar.Get(env).ToString)
  18:     }
  19: seq.Activities.Add(wrt)
  20:  
  21: Dim wfApp As New WorkflowInvoker(seq)
  22: wfApp.Invoke()
  23:  
  24: Console.WriteLine("2回目の実行")
  25: wfApp.Invoke()
  26:  
  27: Console.WriteLine("3回目の実行")
  28: wfApp.Invoke()

ランダムで生成した値を標準出力にて出力する、というワークフローです。ところがこれを実際に実行すると次のようになります。

image

このように毎回同じ値が出力されています。これはアクティビティコンテキストによる実行制御に関連した挙動で、アクティビティの式等はそのままだと実行時に再評価は行わずに生成時にだけ評価を行う、というものです。先程のロジックで言うと、WorkflowInvoker(seq) とした段階で、Assign アクティビティに記述している Value = (New Random).Next(1, 100) の部分は実行され、その結果が保持されてしまっているのです。

これを実行時に毎回評価するには次のように記述します。

1: Dim ass As New Assign(Of Integer) With
   2:     {
   3:         .To = wfVar,
   4:         .Value = New VisualBasicValue(Of Integer)("New Random().Next(1, 100)")
   5:      }

VisualBasicValue クラスを利用する事で、ワークフローの実行時に再評価を行うように動作してくれます。

image

このように少し注意して利用する必要がありますので、コード上から WF を利用する際は気を付けてください。また、今回のサンプルコードはもう一つ問題があるのですが、それは別のエントリで書きたいと思います。

0 件のコメント:

コメントを投稿