2011-08-12 2 views
17

以下の例のように、2つの汎用リストの違いを見つけようとしています。 t1とt2には同じプロパティが含まれていますが、それらは同じオブジェクトではないため、IEqualityComparerを実装する必要があります。LinqカスタムIEqualityComparerを除いて

この例では動作しているようですが、実際のクラスにはいくつかのプロパティがあり、他のいくつかのクラスでも同じことをする必要があります。

私は車輪を再発明しているかどうか疑問に思っていましたか?

2つのオブジェクトのすべてのプロパティを比較する簡単な方法はありますか?現時点では、単純な型を含むクラスには本当に対処する必要がありますが、他のクラスのインスタンスを含むクラスで動作する比較関数があります。私は通常のために行く

void Main() 
{ 
    var t1 = new Sizes { Name = "Test" , Size = 1} ; 
    var t2 = new Sizes { Name = "Test" , Size = 1} ; 

    var list1 = new List<Sizes>(); 
    var list2 = new List<Sizes>(); 
    list1.Add(t1); 
    list2.Add(t2); 

    var differences = list2.Except(list1 , new SizesComparer());  
    // differences should be empty. 
} 


public class Sizes 
{ 
    public string Name { get; set; } 
    public int Size { get; set; } 
} 

public class SizesComparer : IEqualityComparer<Sizes> 
{ 
    bool IEqualityComparer<Sizes>.Equals(Sizes x, Sizes y) 
    {    
     return (x.Name.Equals(y.Name) && x.Size.Equals(y.Size));   
    } 

    int IEqualityComparer<Sizes>.GetHashCode(Sizes obj) 
    { 
     if (Object.ReferenceEquals(obj, null)) 
      return 0;    

     return obj.Name.GetHashCode() + obj.Size;  
    } 
} 
+1

参照IEnumerable.Except()とカスタム比較子 - http://stackoverflow.com/q/1299513/485076 – sll

答えて

4

私は早くに説明することができませんでした使用して終了ソリューションを、それは私の問題ではありません、それは私はそれができるということで何をしたいん特定のクラスに限定されるものではありません。

Newtonsoft.Jsonライブラリを使用してオブジェクトを文字列にシリアル化し、結果を比較します。これには、匿名クラスとネストされたクラスを使用する利点もあります。

私は、両方のオブジェクトで最初にGetHashCodeを呼び出し、それが一致した場合、このルーチンで一致するオブジェクトが2回シリアル化されることを意味するEqualsを呼び出していると仮定しています。

public class JSonEqualityComparer<T> : IEqualityComparer<T> 
{ 
    public bool Equals(T x, T y) 
    {   
     return String.Equals 
     ( 
      Newtonsoft.Json.JsonConvert.SerializeObject(x), 
      Newtonsoft.Json.JsonConvert.SerializeObject(y) 
     );     
    } 

    public int GetHashCode(T obj) 
    {       
     return Newtonsoft.Json.JsonConvert.SerializeObject(obj).GetHashCode();   
    }    
}  


public static partial class LinqExtensions 
{ 
    public static IEnumerable<T> ExceptUsingJSonCompare<T> 
     (this IEnumerable<T> first, IEnumerable<T> second) 
    { 
     return first.Except(second, new JSonEqualityComparer<T>()); 
    } 
} 

あなたは、たとえば、ExceptUsingJSonCompareを除いて交換にそれを使用する:

var differences = list2.ExceptUsingJSonCompare(list1); 
0

ベストな方法は、それぞれにユニーク/複合キーを持っているobjectandあなただけの重要な部分を比較してはいけないその方法は他のビットを比較する必要がしようとしています。

Reflectionを使用すると、クラスの各パブリックプロパティ(非常に一般的です)を比較して比較することができますが、それは遅くなります。

32

あなたのような何かを試みることができる:

var differences = list2.Where(l2 => 
    !list1.Any(l1 => l1.Name == l2.Name && l1.Size == l2.Size)); 
+0

同じタイプのリストにオブジェクトを追加すると、これは完全に機能します。 –

+1

ありがとうございます。 IEqualityComparerを使用するよりもはるかに簡潔です – garyh

関連する問題