2009-08-24 10 views
2

を使用していません。Enumerable.Exceptは、私は、カスタム等値比較を除く方法を使用しようと、それが動作していない私のカスタムの比較子

私の等値比較:

public class BusinessObjectGuidEqualityComparer<T> : IEqualityComparer<T> where T : BusinessObject 
{ 
    #region IEqualityComparer<T> Members 

    /// <summary> 
    /// Determines whether the specified objects are equal. 
    /// </summary> 
    /// <param name="x">The first object of type <paramref name="T"/> to compare.</param> 
    /// <param name="y">The second object of type <paramref name="T"/> to compare.</param> 
    /// <returns> 
    /// <see langword="true"/> If the specified objects are equal; otherwise, <see langword="false"/>. 
    /// </returns> 
    public bool Equals(T x, T y) 
    { 
     return (x == null && y == null) || (x != null && y != null && x.Guid.Equals(y.Guid)); 
    } 

    /// <summary> 
    /// Returns a hash code for this instance. 
    /// </summary> 
    /// <param name="obj">The object to get the hash code.</param> 
    /// <returns> 
    /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
    /// </returns> 
    /// <exception cref="T:System.ArgumentNullException"> 
    /// The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null. 
    /// </exception> 
    public int GetHashCode(T obj) 
    { 
     if (obj == null) 
     { 
      throw new ArgumentNullException("obj"); 
     } 

     return obj.GetHashCode(); 
    } 

    #endregion 
} 

私の使い方を除く:

BusinessObjectGuidEqualityComparer<Area> comparer = new BusinessObjectGuidEqualityComparer<Area>(); 
IEnumerable<Area> toRemove = this.Areas.Except(allocatedAreas, comparer); 
IEnumerable<Area> toAdd = allocatedAreas.Except(this.Areas, comparer); 

奇妙なことに、私はデフォルトの1が使用されている私のカスタム等値比較子を提供し、私は間違って何をするんイベントです?

ありがとうございました。あなたの等値比較で

+0

あなたのコメントを再;私は私のテストリグ、働く... –

+0

を表示するために私の例を更新します(ちょうど脇 - 最終的な問題は、*完全な*コードサンプルを提供することの重要性を示しています...) –

答えて

4

私はこれをテストしたマルクと同様に、すべては私のコードでてToArrayに気づく、私の推測では、あなたがLINQ遅延実行によって捕捉されていることである、うまく呼び出されています。このによるトレース時

注、私はGetHashCodeメソッドは、比較演算でヌルオブジェクトに対して呼び出されることはありません気づきました。

覚えておいて、MiscUtilは、あなたが見る、このようなものをインラインで行うための素晴らしい方法があります:Can I specify my explicit type comparator inline?

それともがexceptために、これを適応させることができます:Distinct list of objects based on an arbitrary key in LINQ

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 { 

    public class BusinessObject { 
     public Guid Guid { get; set; } 
    } 

    public class BusinessObjectGuidEqualityComparer<T> : IEqualityComparer<T> where T : BusinessObject { 
     #region IEqualityComparer<T> Members 

     public bool Equals(T x, T y) { 
      return (x == null && y == null) || (x != null && y != null && x.Guid.Equals(y.Guid)); 
     } 

     /// </exception> 
     public int GetHashCode(T obj) { 
      if (obj == null) { 
       throw new ArgumentNullException("obj"); 
      } 

      return obj.GetHashCode(); 
     } 

     #endregion 
    } 

    class Program { 
     static void Main(string[] args) { 

      var comparer = new BusinessObjectGuidEqualityComparer<BusinessObject>(); 

      List<BusinessObject> list1 = new List<BusinessObject>() { 
       new BusinessObject() {Guid = Guid.NewGuid()}, 
       new BusinessObject() {Guid = Guid.NewGuid()} 
      }; 

      List<BusinessObject> list2 = new List<BusinessObject>() { 
       new BusinessObject() {Guid = Guid.NewGuid()}, 
       new BusinessObject() {Guid = Guid.NewGuid()}, 
       null, 
       null, 
       list1[0] 
      }; 

      var toRemove = list1.Except(list2, comparer).ToArray(); 
      var toAdd = list2.Except(list1, comparer).ToArray(); 

      // toRemove.Length == 1 
      // toAdd.Length == 2 
      Console.ReadKey(); 
     } 
    } 
} 
+0

それはそうです! IEqualityComparerメンバは、それを反復処理するときに呼び出されるので、toRemove.ToList()を試みました。ForEach(...);これが機能します。 – Enyra

1

方法が一致しません。オブジェクトのGUIDを比較していますが、GetHashCodeメソッドでは、GUIDではなく参照に基づいた既定の実装が使用されます。 GUIDが同じでも、異なるインスタンスが異なるハッシュコードを取得するため、Equalsメソッドは使用されません。

public int GetHashCode(T obj) { 
    if (obj == null) { 
     throw new ArgumentNullException("obj"); 
    } 
    return obj.Guid.GetHashCode(); 
} 
+0

はい、あなたが正しいですが、それはありませんGetHashCodeでもEqualsでも呼び出されるので、まだ問題は解決していません。 – Enyra

3

試してみてください:

は、それはあなたが比較しているものであるとして、 GetHashCode方法でGUIDのハッシュコードを取得します

public int GetHashCode(T obj) { 
    return obj == null ? 0 : obj.Guid.GetHashCode(); 
} 

あなたのハッシュコードが一致しなければならない平等を(あるいは、少なくとも、それと矛盾しない)。あなたの等価性は "nullsは等しい、そうでなければguidを比較する"と言います。内部的には、私はExceptGetHashCodeis so importantを取得理由を説明HashSet<T>、使用しています期待しています。ここで


が正常に動作します(上記GetHashCodeを使用して)私のテストリグです:

public abstract class BusinessObject { 
    public Guid Guid { get; set; } 
} 
class Area : BusinessObject { 
    public string Name { get; set; } 
    static void Main() { 
     Guid guid = Guid.NewGuid(); 
     List<Area> areas = new List<Area> { 
      new Area { Name = "a", Guid = Guid.NewGuid() }, 
      new Area { Name = "b", Guid = guid }, 
      new Area { Name = "c", Guid = Guid.NewGuid() }, 
     }; 
     List<Area> allocatedAreas = new List<Area> { 
      new Area { Name = "b", Guid = guid}, 
      new Area { Name = "d", Guid = Guid.NewGuid()}, 
     }; 
     BusinessObjectGuidEqualityComparer<Area> comparer = 
      new BusinessObjectGuidEqualityComparer<Area>(); 
     IEnumerable<Area> toRemove = areas.Except(allocatedAreas, comparer); 
     foreach (var row in toRemove) { 
      Console.WriteLine(row.Name); // shows a & c, since b is allocated 
     } 
    } 
} 

バージョンが動作しない場合は、あなたがしているかについて何かを掲示する必要があるとしています私のためにうまく動作するので(上記)、それを使用してください。

+0

IEqualityComparerドキュメントが定義されている場合、そのGetHashCodeはこの例外をスローします。だから私はそれをcorrent実装したと仮定します。しかし、とにかくそれは私の問題を解決しません、IEqualityComparerメンバーはまったく呼び出されません。 – Enyra

+0

私の推測は、遅延実行によってトリップされました。 –

+0

可能かもしれません;-p –

関連する問題