2010-12-13 12 views
3

辞書のキーとして式の種類を使用するにはどうすればよいですか?式<Func<object>を辞書のキーとして使用

私はExpressionインスタンスで遊んだばかりですが、私がしたいことが可能かどうかはわかりません。

私は試したときと同じ2つの式が同じではないようですが、式をキーとして辞書にエントリを入れることはできますが、キーが含まれているかどうかを辞書に尋ねるとfalseを返します。非常に同じ表現のインスタンス。

TypeToTest test = new TypeToTest(); 
Expression<Func<object>> expression =()=>test.PropertyA; 
IDictionary<Expression<Func<object>>,bool> dictionary = new Dictionary<Expression<Func<object>>, bool>(); 
dictionary[expression] = true; 
Assert.That (dictionary.ContainsKey(expression), Is.True); 
Assert.That (dictionary.ContainsKey(()=>test.PropertyA), Is.True); 

上記の最後の行は失敗します。

目的は、オブジェクトのプロパティまたはメソッドに適用される一連のルールを定義する能力を持つことです。たとえば、プロパティが編集可能な場合、または辞書内の特定のキーを持つ値削除することができます。私は編集可能であるかどうかを判断するオブジェクトにフラグを持たせたくないということです(編集可能性は異なるプロパティに応じて異なる可能性があります)。また、それが削除可能かどうかを判断する別のクラスが、関連するルールを維持する責任を負います将来オブジェクトが拡張されるにつれて、オブジェクトの構成部分の編集可能性/アクセシビリティ/削除可能性を記述するために、より多くの規則が追加され得るように、オブジェクトを伴う。それが意味をなさないならば。

hereのような投稿がありましたが、これはプロパティ名に基づいているようですが、メソッドと引数をキー入力することができるようにしたいので、保持するオブジェクトの編集可能性を判断することができますキーに基づいた辞書で

このようなことは可能でしょうか、それとも空のパイですか?

答えて

4

異なる参照を比較すると、このタイプがEqualsをオーバーライドしないか、IEquatable<T>を実装しない場合に、これが予想される動作です。 (おそらく単純にToString()を比較する)カスタムコンペアラを書き、それを辞書に渡しますが、IMO Expressionはキーの選択肢としてはあまり適していません。

以下はであり、必ずしもToString()による堅牢な使用ではありません。;自分の裁量で使用します。

class Program { 
    static void Main() { 
     TypeToTest test = new TypeToTest(); 
     Expression<Func<object>> expression =() => test.PropertyA; 
     IDictionary<Expression<Func<object>>, bool> dictionary = 
      new Dictionary<Expression<Func<object>>, bool>(
       new ToStringComparer<Expression<Func<object>>>()); 
     dictionary[expression] = true; 

     bool x = dictionary.ContainsKey(expression), // true 
      y = dictionary.ContainsKey(() => test.PropertyA); // true 
    } 
} 
class ToStringComparer<T> : IEqualityComparer<T> where T : class { 
    public bool Equals(T x, T y) { 
     if ((x == null && y == null) || ReferenceEquals(x,y)) return true; 
     if (x == null || y == null) return false; 
     return x.ToString() == y.ToString(); 
    } 
    public int GetHashCode(T obj) { 
     return obj == null ? 0 : obj.ToString().GetHashCode(); 
    } 
} 
+0

なぜあなたはそのキーの良い選択ではないと思いますか?タイプ/タイプが拡張されている(別のインターフェースといっしょに) –

+0

@Samの場合、各プロパティ/メソッドのアクセス可能性を個別に制御できるように思われます。例えば; 'x => x.A'は' y => y.A'と同じ表現ですか?エクスプレッションがキャプチャされた変数ラッパーであるオブジェクトインスタンスをキャプチャするとどうなりますか? –

+0

このための素晴らしい解決策。 – IamStalker

2

Expressionタイプのサブクラスは、それらが困難として、辞書のキーを使用すること、EqualsGetHashCodeメソッドをオーバーライドしません。あなたの辞書は参照の平等を使用しており、2つの出現は()=>test.PropertyAの2つの異なる式ツリーオブジェクトを生成します。

独自のIEqualityComparer<Expression>実装を作成し、それを辞書コンストラクタに渡すことができます。あなたの比較者では、それぞれExpressionクラスを扱い、それらのプロパティを比較したEqualsGetHashCodeメソッドを記述します。

+0

'Expression'が' GetHashCode'をオーバーライドするので、 'IEqualityComparer '実装は実装を委譲できるかもしれません(等しいインスタンスが同じハッシュコードを与えることを確認するだけです)。 – Richard

関連する問題