2010-02-10 27 views
5

tôi đang tạo ra một lớp tổng quát để giữ widget và tôi đang gặp khó khăn thực hiện chứa phương pháp:không thể so sánh Generic Values ​​

public class WidgetBox<A,B,C> 
{ 
    public bool ContainsB(B b) 
    { 
     // Iterating thru a collection of B's 
     if(b == iteratorB) // Compiler error. 
     ... 
    } 
} 

Lỗi: Operator '==' không thể được áp dụng cho toán hạng của loại ' V 'và' V '

Nếu tôi không thể so sánh các loại, tôi phải triển khai như thế nào? Làm thế nào để từ điển, danh sách, và tất cả các container chung khác làm điều đó ??

+0

thể trùng lặp của [Có thể không được toán tử == áp dụng cho các loại chung trong C#?] (http://stackoverflow.com/questions/390900/cant-operator-be-applied-to-generic-types-in-c) – nawfal

Trả lời

7

Bạn có một vài tùy chọn ở đây

Đầu tiên là để sử dụng Object.Equals:

if(b.Equals(iteratorB)) { 
    // do stuff 
} 

Hãy cẩn thận sử dụng tùy chọn này; nếu B không ghi đè Object.Equals thì tổng hợp mặc định là bình đẳng tham chiếu khi B là loại tham chiếu và bình đẳng giá trị khi B là loại giá trị. Đây có thể không phải là hành vi mà bạn đang tìm kiếm và là lý do tại sao mà không có thông tin bổ sung, tôi sẽ xem xét một trong hai tùy chọn tiếp theo.

Thứ hai là để thêm một hạn chế mà BIComparable:

public class WidgetBox<A, B, C> where B : IComparable 

để

if(b.CompareTo(iteratorB) == 0) { 
    // do stuff 
} 

Một phần ba là để yêu cầu một IEqualityComparer<B> được truyền cho constructor của WidgetBox

public class WidgetBox<A, B, C> { 
    IEqualityComparer<B> _comparer; 
    public WidgetBox(IEqualityComparer<B> comparer) { 
     _comparer = comparer; 
    } 
    // details elided 
} 

Sau đó:

if(_comparer.Equals(b, iteratorB)) { 
    // do stuff 
} 

Với tùy chọn cuối cùng này, bạn có thể cung cấp một quá tải mà mặc định là EqualityComparer<T>.Default:

public WidgetBox() : this(EqualityComparer<T>.Default) { } 
+1

Tùy thuộc vào loại và liệu bạn chỉ quan tâm đến bình đẳng (so với nhỏ hơn/lớn hơn/bằng/etc) thường hiệu quả hơn khi sử dụng IEqualityComparer như trái ngược với IComparer vì sự bình đẳng thường có thể loại trừ rất nhanh chóng như với các chuỗi khác nhau ent độ dài. – Josh

3

Không phải tất cả các đối tượng đều thực hiện == nhưng tất cả đều sẽ có bằng (mặc dù nó có thể được kế thừa từ Object.Equals).

public class WidgetBox<A,B,C> 
{ 
    public bool ContainsB(B b) 
    { 
     // Iterating thru a collection of B's 
     if(b.Equals(iteratorB)) 
     ... 
    } 
} 
0
if (b != null) 
    if (b.Equals(iteratorB)) 
     ... 
2

Tại thời gian biên dịch, không có gì bảo đảm rằng các loại trong các loại lập luận B cung cấp một nhà điều hành bình đẳng.

Thay vào đó, bạn có thể làm điều này:

var comparer = EqualityComparer<B>.Default; 
foreach (B item in items) { 
    if (comparer.Equals(b, item)) { 
     .... 
    } 
} 
3

Để thêm vào câu trả lời của Jason, bạn cũng có thể thêm where T : IEquatable<T> hơn IComparable. Điều này cung cấp quá tải phương thức Equals chấp nhận thông số T.

public class WidgetBox<A,B,C> where B : IEquatable<B> 
{ 
    public bool ContainsB(B b) 
    { 
     // Iterating thru a collection of B's 
     if(b.Equals(iteratorB)) 
     ... 
    } 
} 

Điều này có thể thích hợp hơn để chỉ đơn giản bằng cách sử dụng cung cấp Object.Equals phương pháp, vì đó kiểm tra sự tương đương của hai tài liệu tham khảo đối tượng (Tôi tin) và như vậy có thể không cung cấp hoàn toàn chức năng mà bạn muốn (ví dụ, nếu bạn muốn hai đối tượng Person có cùng thuộc tính SSN được coi là bằng nhau hoặc tương tự như vậy).

Nhưng để trả lời câu hỏi của bạn về "làm thế nào để tất cả các bộ sưu tập .NET làm điều đó", tôi tin rằng phương pháp Equals (không có ràng buộc) là câu trả lời của bạn.

0

Nếu bạn có thể nhận được ngay với nó trong trường hợp của bạn thì tất cả phải mất là một hạn chế lớp trên B

public class WidgetBox<A,B,C> where B : class 

rằng sẽ loại bỏ các vấn đề

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