3

現在、引数として を使用する関数がありFunc<T1, T2>ます。特定の状況で式ツリーをトラバースできるように、 as 引数
を使用する必要があります。Expression<Func<T1, T2>>

すべての呼び出しで関数を使用したいのでCompile()、式が必要になります。すべての式を再コンパイルする必要がないように、それらを辞書に入れたいと思います。

私のメソッドへの呼び出しは次のようになります。

var foo = MyFunc(x => x.Field);

Expression辞書のキーとしての使用に関して、次の解決策は正しいですか?

static Dictionary<Expression<Func<T1, T2>>, Func<T1, T2>> s_functions = new Dictionary<Expression<Func<T1, T2>>, Func<T1, T2>>();

public T2 MyFunc(Expression<Func<T1, T2>> selectorExpression)
{
    if (!s_functions.ContainsKey(selectorExpression))
    {
        s_functions.Add(selectorExpression, selectorExpression.Compile());
    }

    Func<T1, T2> selector = s_functions[selectorExpression];
}

編集

パフォーマンスの観点からそれを解決する良い方法は何でしょうか?

4

2 に答える 2

4

残念ながらそうではありませんが、問題はパフォーマンスのバグとしてのみ現れます。

問題はExpression<TDelegate>実装されていないIEquatable<Expression<TDelegate>>ため、ディクショナリで使用されるデフォルトの等値比較子は参照の等値のみを実行します。これは、同じ式の異なるインスタンスが同一のものと比較されないことを意味し、ヒットするはずのキャッシュ ミスにつながります。一方、異なる式のインスタンスは常に異なるものと比較されるため、論理的なバグはありません。

ディクショナリに独自の等値比較子を提供することでこの問題を解決できますが、それを書かなければならないという小さな問題もあります。

明るい面としては、利便性と引き換えに、元の実装と同じパフォーマンス バグを持つ (ただし、スコープが縮小された) 比較演算子を作成できる可能性があります。遭遇する!たとえば、ToString()表現の同等性に基づいて比較を試みたい場合があります。比較子が誤検知を生成しない限り、改善の余地しかありません。

于 2012-11-13T16:59:54.113 に答える
2

キーとして使用selectorExpression.ToString()します。異なるパラメーター名を使用した同等の式は異なる文字列を生成するため、完全ではありませんが、非常に単純なアプローチです。

テスト:

Expression<Func<int,int>> expr = x => x * x;
MessageBox.Show(expr.ToString()); // ==> "x => (x * x)"
于 2012-11-13T17:45:28.847 に答える