VB.NET 式 (たとえばデータベースから) を含む文字列を受け入れ、ワークフローの現在のスコープで使用可能な変数を使用してその文字列を評価し、結果を返す単純な WF4 アクティビティを作成しようとしています。残念ながら、私が試した方法では、プレーンオンであろうとActivity
本格的なオンであろうとNativeActivity
、壁にぶつかり続けています。
私の最初の試みは単純なアクティビティで、オブジェクトを入力として与えられた式を評価する単純なクラスを作成することができました。
public class Eval<T, TResult> : Activity<TResult>
{
[RequiredArgument]
public InArgument<T> Value { get; set; }
public Eval(string predicate)
{
this.Implementation = () => new Assign<TResult>
{
Value = new InArgument<TResult>(new VisualBasicValue<TResult>(predicate)),
To = new ArgumentReference<TResult>("Result")
};
}
public TResult EvalWith(T value)
{
return WorkflowInvoker.Invoke(this, new Dictionary<string, object>{ {"Value", value } });
}
}
これはうまくいき、次の式は 7 に評価されます。
new Eval<int, int>("Value + 2").EvalWith(5)
残念ながら、式の文字列は としてではなくコンストラクターの引数として与えられるため、思い通りに使用することはInArgument<string>
できません。そのため、ワークフローに簡単に組み込む (ドラッグ アンド ドロップする) ことができません。私の2番目の試みはNativeActivity
、その厄介なコンストラクターパラメーターを取り除くために試して使用することでした:
public class NativeEval<T, TResult> : NativeActivity<TResult>
{
[RequiredArgument] public InArgument<string> ExpressionText { get; set; }
[RequiredArgument] public InArgument<T> Value { get; set; }
private Assign Assign { get; set; }
private VisualBasicValue<TResult> Predicate { get; set; }
private Variable<TResult> ResultVar { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
Predicate = new VisualBasicValue<TResult>();
ResultVar = new Variable<TResult>("ResultVar");
Assign = new Assign { To = new OutArgument<TResult>(ResultVar), Value = new InArgument<TResult>(Predicate) };
metadata.AddVariable(ResultVar);
metadata.AddChild(Assign);
}
protected override void Execute(NativeActivityContext context)
{
Predicate.ExpressionText = ExpressionText.Get(context);
context.ScheduleActivity(Assign, new CompletionCallback(AssignComplete));
}
private void AssignComplete(NativeActivityContext context, ActivityInstance completedInstance)
{
Result.Set(context, ResultVar.Get(context));
}
}
NativeEval
以下で実行してみました。
WorkflowInvoker.Invoke(new NativeEval<int, int>(), new Dictionary<string, object>
{ { "ExpressionText", "Value + 2" }, { "Value", 5 } });
しかし、次の例外があります。
アクティビティ '1: NativeEval' は、アクティビティ '1: NativeEval' のスコープで宣言されているため、この変数にアクセスできません。アクティビティは、独自の実装変数にのみアクセスできます。
だから私はに変更metadata.AddVariable(ResultVar);
しましmetadata.AddImplementationVariable(ResultVar);
たが、その後、別の例外が発生しました:
ワークフロー ツリーの処理中に次のエラーが発生しました: 'VariableReference': 参照された変数オブジェクト (名前 = 'ResultVar') は、このスコープでは表示されません。このスコープで表示される同じ名前の別の場所参照が存在する可能性がありますが、同じ場所を参照していません。
ここで.ScheduleFunc()
説明されているようにアクティビティをスケジュールするために使用しようとしましたが、返された結果は常にでした(ただし、奇妙なことに、例外はスローされませんでした)。VisualBasicValue
null
私は困惑しています。WF4 のメタプログラミング モデルは のメタプログラミング モデルよりもはるかに難しいように見えますがSystem.Linq.Expressions
、これは難しく、しばしば当惑します (通常のメタプログラミングのように) が、少なくとも私はそれに頭を悩ませることができました。単純な古いプログラムではなく、持続可能で再開可能、非同期、再配置可能なプログラムを表現する必要があるという複雑さが増しているためだと思います。
編集:私が経験している問題は、ハードコーディングされていない式を評価しようとしていることが原因であるとは思わないので、次の変更を に加えNativeActivity
て、静的な式を持たせることができます:
交換
Predicate = new VisualBasicValue<TResult>();
と
Predicate = new VisualBasicValue<TResult>("ExpressionText.Length");
そして、行を削除します
Predicate.ExpressionText = ExpressionText.Get(context);
これらの行で式が静的であっても、同じエラーが発生します。
EDIT2:この記事は、私が得ていた例外に対処しました。変数と子アクティビティの両方を「実装」に変更する必要があったため、次のようにしました。
metadata.AddVariable(ResultVar);
metadata.AddChild(Assign);
これに変更:
metadata.AddImplementationVariable(ResultVar);
metadata.AddImplementationChild(Assign);
そして、すべての例外がなくなりました。残念ながら、次の行はまったく何もしないことが明らかになりました。
Predicate.ExpressionText = ExpressionText.Get(context);
ExpressionText
実行時に a のプロパティを変更しVisualBasicValue
ても効果はありません。ILSpy で簡単に確認すると、その理由が明らかになります。式のテキストは、CacheMetadata()
が呼び出されたときにのみ評価され、式ツリーに変換されます。その時点では、式はまだわかりません。ノーオペレーション。NativeActivityMetadata
独自の CacheMetadata オーバーライド メソッドで取得したオブジェクトを保存してから、リフレクションを使用してVisualBasicValue
'sへの呼び出しを強制しようとCacheMetadata()
しましたが、別の不可解な例外 (AmbiguousMatchException タイプの「あいまいな一致が見つかりました。」) がスローされました。
現時点では、動的式をワークフローに完全に統合して、スコープ内のすべての変数をワークフローに公開することはできないようです。Eval
クラス内でクラスで使用されるメソッドがあると思いますNativeEval
。