2011-08-12 31 views
17

Tôi đang cố gắng tìm sự khác biệt giữa hai danh sách chung chung, như trong ví dụ bên dưới. Mặc dù t1 và t2 chứa các thuộc tính giống nhau, chúng không phải là cùng một đối tượng, vì vậy tôi cần phải triển khai IEqualityComparer.LINQ Ngoại trừ IEqualityComparer tùy chỉnh

Điều này dường như đang làm việc với ví dụ này, nhưng lớp thực sự có một số thuộc tính khác và tôi cũng cần phải làm tương tự với một vài lớp khác.

Vì vậy, tôi đã tự hỏi nếu tôi tái phát minh ra bánh xe?

Có phương pháp so sánh tất cả các thuộc tính của hai đối tượng dễ dàng hơn không? Tại thời điểm này, tôi thực sự chỉ cần đối phó với lớp có chứa các kiểu đơn giản, nhưng nó sẽ là tốt đẹp Tôi có một so sánh làm việc với các lớp có chứa các thể hiện của các lớp khác.

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

Xem IEnumerable.Except() và một comparer tùy chỉnh - http://stackoverflow.com/q/1299513/485076 – sll

Trả lời

4

Các giải pháp mà tôi đã kết thúc sử dụng không thể được mô tả như nhanh, nhưng đó không phải là một mối quan tâm của tôi và nó làm những gì tôi muốn ở chỗ nó có thể tái sử dụng và không bị giới hạn ở bất kỳ lớp học cụ thể nào.

Nó sử dụng thư viện Newtonsoft.Json để tuần tự hóa đối tượng thành chuỗi và sau đó so sánh kết quả. Điều này cũng có lợi thế là làm việc với các lớp ẩn danh và các lớp lồng nhau.

Tôi giả định rằng cách so sánh hoạt động là lần đầu tiên nó gọi GetHashCode trên cả hai đối tượng và nếu chúng khớp với nó thì gọi Equals, trong thói quen này sẽ có nghĩa là các đối tượng trùng khớp sẽ được tuần tự hai lần.

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>()); 
    } 
} 

Để sử dụng nó, bạn trao đổi Trừ với ExceptUsingJSonCompare, ví dụ:

var differences = list2.ExceptUsingJSonCompare(list1); 
0

Cách tốt nhất tôi thường dùng là thử có khóa duy nhất/tổng hợp trong mỗi đối tượng và cách bạn chỉ so sánh phần chính và không cần phải so sánh các bit khác.

Bạn có thể sử dụng Phản ánh sẽ đi qua từng thuộc tính công khai của lớp (sẽ rất chung chung) và so sánh chúng, nhưng điều đó sẽ chậm hơn.

32

Bạn có thể thử một cái gì đó như:

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

Điều này hoạt động hoàn hảo nếu bạn thêm các đối tượng vào danh sách từ cùng một loại. –

+1

Cảm ơn. Ngắn gọn hơn nhiều so với sử dụng IEqualityComparer – garyh

Các vấn đề liên quan