2011-08-10 9 views
3

あなたはこのように、任意の型のオブジェクトのコレクションを保持するために使用される予定のジェネリッククラス内の「REMOVEALL」を使用している場合:まあリスト<T>。汎用クラスの中の.RemoveAll <T>には、述語の変形フォームが必要ですか?

public class SomeClass<T> 
{ 
    internal List<T> InternalList; 

    public SomeClass() { InternalList = new List<T>(); } 

    public void RemoveAll(T theValue) 
    { 
     // this will work 
     InternalList.RemoveAll(x => x.Equals(theValue)); 

     // the usual form of Lambda Predicate 
     // for RemoveAll will not compile 
     // error: Cannot apply operator '==' to operands of Type 'T' and 'T' 
     // InternalList.RemoveAll(x => x == theValue); 
    } 
} 

答えて

2

することは、あなたはこのようにEqualityComparer<T>.Defaultを使用することができます。

public void RemoveAll(T theValue) 
{ 
    // this will work 
    InternalList.RemoveAll(x => EqualityComparer<T>.Default.Equals(x, theValue)); 
} 

コードは(NULL可能なタイプと値型を含む)Tのいずれかのタイプのために働くということ、それは避けまた、TがIEquatable<T>を実装するか、object.Equalsを上書きするケースも処理します。

タイプTは System.IEquatable(T)インターフェイスを実装し、そうであれば、その実装を使用 EqualityComparer(T)を返すかどうかをデフォルトのプロパティをチェック:documentationから。それ以外の場合は、戻り T.

+0

ありがとう、私はこの答えを受け入れたとマークしましたが、奇妙な...チェックマークは緑色に変わっていません。私はあなたの答えがnullableを含むどのような型も扱えるという事実は好きです。 – BillW

+0

私は今それを緑色と見ています....多分遅れがあったかもしれません。 –

4

Tが値型を指定できますので、あなたがしなければならないでしょう

public class SomeClass<T> where T : class 
    { 
    internal List<T> InternalList; 

    public SomeClass() { InternalList = new List<T>(); } 

    public void RemoveAll(T theValue) 
    { 
     // this will work 
     InternalList.RemoveAll(x => x == theValue); 
    } 
    } 

refrefの平等をチェックするだけで実際に欲しいものですが、注意してください。

更新:私はこれを最初に言及するのを忘れましたが、これはもちろんあなたが値の種類のためにそれを使用することができないことを意味します。代替ソートの両方をサポートするために、このようなものを使用して次のようになります。

public abstract class SomeCollection<T> 
{ 
    internal List<T> InternalList; 

    public SomeCollection() { InternalList = new List<T>(); } 

    public abstract void RemoveAll(T theValue); 
} 

public class ReferenceCollection<T> : SomeCollection<T> where T : class 
{ 
    public override void RemoveAll(T theValue) 
    { 
     InternalList.RemoveAll(x => x == theValue); 
    } 
} 

public class ValueCollection<T> : SomeCollection<T> where T : struct 
{ 
    public override void RemoveAll(T theValue) 
    { 
     InternalList.RemoveAll(x => x.Equals(theValue)); 
    } 
} 
+2

次いで良いだろう

InternalList.RemoveAll(x => (object)x == (object)theValue); 

又はEqualsを継承IMO。 –

+0

@Stefanが同意した。それはおそらくもっと良い解決策になるだろう。 – alun

+0

ありがとう、Alun、私はあなたのソリューションの「エレガントなアーキテクチャー」を好んでいます。これはコードの自己文書化の性質に貢献し、私が使用するものです。私はここで複数の回答を「受け入れられた回答」とすることができれば幸いです。あなたの答えとスティーブンスの間に、私は「両世界の最高」を持っていると思います。誓って昨日このコメントを追加しましたが、それは消えました:) – BillW

0

それはTリファレンスと値型のすべての種類のために働く必要があります。

System.ValueType内のequalsのデフォルトの実装は

  // if there are no GC references in this object we can avoid reflection 
      // and do a fast memcmp 
      if (CanCompareBits(this)) 
       return FastEqualsCheck(thisObj, obj); 

      FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

      for (int i=0; i<thisFields.Length; i++) { 
       thisResult = ((RtFieldInfo)thisFields[i]).InternalGetValue(thisObj,false); 
       thatResult = ((RtFieldInfo)thisFields[i]).InternalGetValue(obj, false); 

       if (thisResult == null) { 
        if (thatResult != null) 
         return false; 
       } 
       else 
       if (!thisResult.Equals(thatResult)) { 
        return false; 
       } 
      } 

The .net guidelines state(MS基準源から)次があります。

あなたは値型でEqualsメソッドの実装を検討すべきである System.ValueTypeの既定の実装では、カスタム実装と同様に が実行されないためです。

私は、設計者がSystem.ValueTypesに==の暗黙的な演算子を頼りにして、これが適用可能なより良いバージョンを実装してもらいたいと考えています。あなたができる限りのコードがあるフレキシブルにしたい場合は

0

operator==によって提供 はObject.equalsとObject.GetHashCodeをのオーバーライドを使用EqualityComparer(T)は、コンパイラによって結合され、両方の引数が同じコンパイル時の型を持っている必要が。

object.operator==を使用して明示的基準の比較を使用するか:(オーバーライドおよびランタイム型と見なしてもよい)コンストラクタで任意EqualityComparerを提供

InternalList.RemoveAll(x => x.Equals(theValue)); 
関連する問題