2014-07-24 13 views
7

Tôi muốn đối tượng riêng biệt trong danh sách. Tôi cố gắng thực hiện IEqualityComparer nhưng không thành công. Xin vui lòng nếu ai đó có thể xem xét mã của tôi và cho tôi một số giải thích về IEqualityComparer. Tôi có tình hình sau:Triển khai IEqualityComparer

public class Message 
{ 
    public int x { get; set; } 
    public string y { get; set; } 
    public string z { get; set; } 
    public string w { get; set; } 
} 

public class MessageComparer : IEqualityComparer<Message> 
{ 
    public bool Equals(Message x, Message y) 
    { 
     if (Object.ReferenceEquals(x, y)) return true; 

     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 
     if (x.x == y.x && x.y == y.y && x.z == y.z && x.w == y.w) 
     { 
      return true; 
     } 
     return false; 
    } 

    public int GetHashCode(Message number) 
    { 
     //if (Object.ReferenceEquals(number, null)) return 0; 
     int hashX = number.x.GetHashCode(); 
     int hashY = number.y == null ? 0 : number.y.GetHashCode(); 
     int hashZ = number.z == null ? 0 : number.z.GetHashCode(); 
     int hashW = number.w == null ? 0 : number.w.GetHashCode(); 

     return hashX^hashY^hashZ^hashW; 

    } 
} 

Đây là danh sách của tôi với các đối tượng tin nhắn:

Message m1 = new Message(); 
     m1.x = 1; 
     m1.y = "A"; 
     m1.z = "B"; 
     m1.w = "C"; 

     Message m2 = new Message(); 
     m2.x = 1; 
     m2.y = "A"; 
     m2.z = "B"; 
     m2.w = "C"; 

     Message m3 = new Message(); 
     m3.x = 1; 
     m3.y = "A"; 
     m3.z = "B"; 
     m3.w = "C"; 

     Message m4 = new Message(); 
     m4.x = 2; 
     m4.y = "A"; 
     m4.z = "B"; 
     m4.w = "C"; 

     Message m5 = new Message(); 
     m5.x = 3; 
     m5.y = "W"; 
     m5.z = "D"; 
     m5.w = "C"; 

     Message m6 = new Message(); 
     m6.x = 4; 
     m6.y = "S"; 
     m6.z = "F"; 
     m6.w = "R"; 

     List<Message> collection = new List<Message>(); 
     collection.Add(m1); 
     collection.Add(m2); 
     collection.Add(m3); 
     collection.Add(m4); 
     collection.Add(m5); 

     collection.Distinct(new MessageComparer()); 

Khi tôi gọi riêng biệt() số phương pháp phần tử trong danh sách là như nhau. Cảm ơn bạn.

+1

Bạn đang gán kết quả của các cuộc gọi riêng biệt cho một biến hoặc chỉ kiểm tra danh sách ban đầu? Nếu bạn không chỉ định cho bất cứ điều gì, bạn sẽ cần. 'Distinct()' trả về một 'IEnumerable' thay vì thực hiện cập nhật tại chỗ – eouw0o83hf

+0

Cảm ơn, bạn đã đúng :) – kat1330

Trả lời

11

Hãy thử điều này:

var distinct = collection.Distinct(new MessageComparer()); 

Sau đó sử dụng distinct cho bất cứ điều gì sau đó.

Dường như bạn đang quên đi bản chất không thể thay đổi của IEnumerable<>. Không có phương thức LINQ nào thực sự thay đổi biến ban đầu. Thay vào đó, chúng trả về IEnuerable<T> s chứa kết quả của biểu thức. Ví dụ, chúng ta hãy xem xét một đơn giản List<string> original với nội dung { "a", "a", "b", "c" }.

Bây giờ, hãy gọi original.Add("d");. Phương thức đó không có giá trị trả lại (đó là void). Nhưng nếu sau đó chúng tôi in ra nội dung của original, chúng tôi sẽ thấy { "a", "a", "b", "c", "d" }.

Mặt khác, bây giờ hãy gọi original.Skip(1). Phương thức này không có giá trị trả lại, một trong các loại IEnumerable<string>. Đây là biểu thức LINQ và không thực hiện tác vụ phụ nào trên bộ sưu tập gốc. Do đó, nếu chúng tôi gọi và xem số original, chúng tôi sẽ thấy { "a", "a", "b", "c", "d" }. Tuy nhiên, kết quả từ phương thức sẽ là { "a", "b", "c", "d" }. Như bạn có thể thấy, kết quả bỏ qua một phần tử.

Điều này là do phương pháp LINQ chấp nhận IEnumerable<T> làm tham số. Do đó, họ không có khái niệm về việc thực hiện danh sách ban đầu. Bạn có thể đi qua, thông qua phương pháp mở rộng, một số ReadOnlyCollection và họ vẫn có thể đánh giá thông qua nó. Sau đó, họ không thể thay đổi bộ sưu tập gốc vì bộ sưu tập gốc có thể được viết bằng bất kỳ cách nào.

Tất cả điều đó, nhưng ở dạng bảng. Mỗi dòng bắt đầu với bản gốc { "a", "a", "b", "c" }:

Context  Example function Immutable? Returned Value  Collection after calling 
Collection Add("d")   No   (void)    { "a", "a", "b", "c", "d" }: 
LINQ  Skip(1)    Yes   { "a", "b", "c" } { "a, "a", "b", "c" }: 
2

Bạn không cần phải thực hiện IEqualityComparer:

public class Message 
    { 
     protected bool Equals(Message other) 
     { 
      return string.Equals(x, other.x) && string.Equals(y, other.y) && string.Equals(z, other.z) && string.Equals(w, other.w); 
     } 

     public override bool Equals(object obj) 
     { 
      if (ReferenceEquals(null, obj)) return false; 
      if (ReferenceEquals(this, obj)) return true; 
      if (obj.GetType() != this.GetType()) return false; 
      return Equals((Message) obj); 
     } 

     public override int GetHashCode() 
     { 
      unchecked //Ignores overflows that can (should) occur 
      { 
       var hashCode = x; 
       hashCode = (hashCode*397)^(y != null ? y.GetHashCode() : 0); 
       hashCode = (hashCode*397)^(z != null ? z.GetHashCode() : 0); 
       hashCode = (hashCode*397)^(w != null ? w.GetHashCode() : 0); 
       return hashCode; 
      } 
     } 

     public int x { get; set; } 
     public string y { get; set; } 
     public string z { get; set; } 
     public string w { get; set; } 
    } 
+0

Phụ thuộc vào trường hợp. Nếu loại so sánh này chỉ cần trong một trường hợp riêng biệt, tốt hơn là sử dụng một trình so sánh riêng biệt. Phương pháp Overriding Equals cũng ảnh hưởng đến các địa điểm khác. –

+0

Nó ảnh hưởng đến những nơi khác một cách tích cực, bạn thường muốn thực hiện nó cho một lớp dữ liệu như thế này –

0

Tham khảo link này để biết thông tin chi tiết hơn

http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

IEqualityComparer là một giao diện được sử dụng để tìm đối tượng cho dù đó là Bình đẳng hay không, Bây giờ chúng ta sẽ thấy điều này trong một mẫu mà chúng ta phải tìm sự khác biệt của một đối tượng trong một bộ sưu tập.Giao diện này sẽ triển khai phương thức Bằng (T obj1, T obj2)

lớp công khai trừu tượng Person { chuỗi công khai FirstName {get; bộ; } chuỗi công khai LastName {get; bộ; } chuỗi công khai Địa chỉ {set; được; }}

public enum SortType 
{ 
    ByID, 
    BySalary 
} 

    public class EmployeeDistinctEquality : IEqualityComparer<Employee> 
    { 
     public EmployeeDistinctEquality() 
     { 

     } 

     public bool Equals(Employee x, Employee y) 
     { 
      if (x == null && x == null) 
       return true; 
      else if (x == null || y == null) 
       return false; 
      else if (x.Id == y.Id) 
       return true; 
      else 
       return false; 
     } 

     public int GetHashCode(Employee obj) 
     { 
      return obj.Id.GetHashCode(); 
     } 
    } 

Tham khảo link này để biết thông tin chi tiết hơn

http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html