2016-10-04 14 views
7

Tôi đang sử dụng phương thức Enumerable.Union<TSource> để lấy liên kết của Danh sách tùy chỉnh1 với Danh sách tùy chỉnh2. Nhưng bằng cách nào đó nó không hoạt động như trong trường hợp của tôi. Tôi nhận được tất cả các mục cũng trùng lặp một lần.Cách sử dụng C# LINQ Union để nhận Liên minh Danh sách tùy chỉnh1 với danh sách2

Tôi theo dõi MSDN Link để hoàn thành công việc, nhưng tôi vẫn không thể đạt được điều tương tự.

Tiếp theo là Bộ luật của lớp tùy chỉnh: -

public class CustomFormat : IEqualityComparer<CustomFormat> 
{ 
    private string mask; 

    public string Mask 
    { 
     get { return mask; } 
     set { mask = value; } 
    } 

    private int type;//0 for Default 1 for userdefined 

    public int Type 
    { 
     get { return type; } 
     set { type = value; } 
    } 
    public CustomFormat(string c_maskin, int c_type) 
    { 
     mask = c_maskin; 
     type = c_type; 
    } 

    public bool Equals(CustomFormat x, CustomFormat y) 
    { 
     if (ReferenceEquals(x, y)) return true; 

     //Check whether the products' properties are equal. 
     return x != null && y != null && x.Mask.Equals(y.Mask) && x.Type.Equals(y.Type); 
    } 

    public int GetHashCode(CustomFormat obj) 
    { 
     //Get hash code for the Name field if it is not null. 
     int hashProductName = obj.Mask == null ? 0 : obj.Mask.GetHashCode(); 

     //Get hash code for the Code field. 
     int hashProductCode = obj.Type.GetHashCode(); 

     //Calculate the hash code for the product. 
     return hashProductName^hashProductCode; 
    } 
} 

này tôi kêu gọi như sau: -

List<CustomFormat> l1 = new List<CustomFormat>(); 
l1.Add(new CustomFormat("#",1)); 
l1.Add(new CustomFormat("##",1)); 
l1.Add(new CustomFormat("###",1)); 
l1.Add(new CustomFormat("####",1)); 

List<CustomFormat> l2 = new List<CustomFormat>(); 
l2.Add(new CustomFormat("#",1)); 
l2.Add(new CustomFormat("##",1)); 
l2.Add(new CustomFormat("###",1)); 
l2.Add(new CustomFormat("####",1)); 
l2.Add(new CustomFormat("## ###.0",1)); 

l1 = l1.Union(l2).ToList(); 

foreach(var l3 in l1) 
{ 
    Console.WriteLine(l3.Mask + " " + l3.Type); 
} 

Xin gợi ý cách thích hợp để đạt được cùng!

+3

Có vẻ lạ, nhưng mã của bạn hoạt động nếu bạn a) cung cấp một hàm tạo parameterless cho CustomFormat và chuyển một thể hiện của lớp đó sang phương thức Union - xem https://dotnetfiddle.net/YTVwTI. Câu hỏi sau đó là tại sao Union bỏ qua việc thực hiện IEqualityComparer trong lớp. – stuartd

Trả lời

8

Sự kỳ quặc ở đây là lớp của bạn triển khai IEqualityComparer<CustomClass> thay vì IEquatable<CustomClass>. Bạn có thể chuyển sang một phiên bản khác của CustomClass sẽ được sử dụng làm so sánh, nhưng sẽ thành ngữ hơn để chỉ thực hiện CustomClass triển khai IEquatable<CustomClass> và cũng ghi đè Equals(object).

Sự khác biệt giữa IEquatable<T>IEqualityComparer<T>IEquatable<T> nói: "Tôi biết làm thế nào để so sánh bản thân mình với một thể hiện của T" trong khi IEqualityComparer<T> nói: "Tôi biết làm thế nào để so sánh hai trường hợp của T". Thông tin thứ hai thường được cung cấp riêng - giống như nó có thể được cung cấp cho Union thông qua một thông số khác. Rất hiếm khi một loại để triển khai IEqualityComparer<T> cho loại riêng của mình - trong khi IEquatable<T> chỉ nên sử dụng chỉ để so sánh các giá trị cùng loại.

Dưới đây là triển khai sử dụng các thuộc tính được tự động triển khai để đơn giản và nhiều tên thông số thành ngữ hơn. Tôi có thể thay đổi việc thực thi mã băm bản thân mình và sử dụng các thành viên biểu hiện thân, nhưng đó là một vấn đề khác.

public class CustomFormat : IEquatable<CustomFormat> 
{ 
    public string Mask { get; set; } 
    public int Type { get; set; } 

    public CustomFormat(string mask, int type) 
    { 
     Mask = mask; 
     Type = type; 
    } 

    public bool Equals(CustomFormat other) 
    { 
     if (ReferenceEquals(this, other)) 
     { 
      return true; 
     } 
     return other != null && other.Mask == Mask && other.Type == Type; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as CustomFormat); 
    } 

    public override int GetHashCode() 
    { 
     // Get hash code for the Name field if it is not null. 
     int hashProductName = Mask == null ? 0 : Mask.GetHashCode(); 

     //Get hash code for the Code field. 
     int hashProductCode = Type.GetHashCode(); 

     //Calculate the hash code for the product. 
     return hashProductName^hashProductCode; 
    } 
} 

Bây giờ nó không giúp điều đó (như đã nêu trong nhận xét) tài liệu cho Enumerable.Union là sai. Nó hiện đang khẳng định:

Giá trị mặc định comparer bình đẳng, Default, được sử dụng để so sánh giá trị của các loại mà thực hiện giao diện chung IEqualityComparer<T>.

Nó nên nói cái gì đó như:

Các comparer bình đẳng mặc định, Default, được sử dụng để so sánh giá trị khi một cụ IEqualityComparer<T> không được cung cấp. Nếu T thực hiện IEquatable<T>, trình so sánh mặc định sẽ sử dụng triển khai đó. Nếu không, nó sẽ sử dụng việc thực hiện Equals(object).

+0

Tôi đã thử triển khai nhưng dường như không giải quyết được vấn đề. Vui lòng xem mã [link] (https://dotnetfiddle.net/YTVwTI). Nó cho thấy không có lỗi nhưng các mục trùng lặp được hiển thị. – JDoshi

+0

@JDoshi: Fiddle đó vẫn thực hiện 'IEqualityComparer '. Mã tôi đã đưa ra (thực hiện 'IEquatable ' thay thế) * làm * làm việc với ví dụ bạn đã cung cấp. –

+0

Thực ra tôi đã chỉnh sửa trong cùng một câu đố đó và chia sẻ liên kết với bạn được chia sẻ bởi stuartd. Vì vậy, bạn vô tình chia sẻ sai fiddle. Xin lỗi vì lỗi: ( – JDoshi

3

Bạn cần chuyển phiên bản IEqualityComparer sang phương thức Union. Phương pháp này có quá tải để vượt qua trong trình so sánh của bạn.

Các giải pháp dễ nhất và xấu nhất là

var comparer = new CustomFormat(null,0); 

l1 = l1.Union(l2, comparer).ToList(); 

Bạn đã thực hiện một số sai lầm trong việc thực hiện của bạn. Bạn không nên triển khai phương thức IEqualityComparer trên loại của mình (CustomFormat), nhưng trên một lớp riêng biệt, như CustomFormatComparer.

Trên loại của bạn (CustomFormat), bạn nên triển khai IEquatable.

+4

Liên kết MSDN cho Liên minh là sai lạc, sau đó, như nó nói _ "Trình so sánh bình đẳng mặc định, Mặc định, được sử dụng để so sánh các giá trị của các loại thực hiện giao diện chung IEqualityComparer . ** Để so sánh loại dữ liệu tùy chỉnh, bạn cần để thực hiện giao diện này và cung cấp các phương thức GetHashCode và Equals của riêng bạn cho kiểu **. "_ nó không quy định điều này phải nằm trong một lớp riêng biệt. – stuartd

+0

@Jehof Bạn có thể giải thích cách sử dụng 'IEquatable' trong trường hợp này không. Ở đây, việc thực thi 'IEquatable' trực tiếp và không có hiệu suất' IEqualityComparer' do lỗi 'Union' được sử dụng. – JDoshi

+0

@JDoshi: Không, nó không - thực hiện 'IEquatable ' thực sự là con đường phía trước ở đây. –

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