2010-04-29 27 views
114

Tôi muốn lớp Food của mình có thể kiểm tra bất cứ khi nào nó bằng với một phiên bản khác của Food. Sau này tôi sẽ sử dụng nó chống lại một Danh sách và tôi muốn sử dụng phương thức List.Contains() của nó. Tôi có nên triển khai IEquatable<Food> hoặc chỉ ghi đè Object.Equals() không? Từ MSDN:Sự khác biệt giữa IEquatable và chỉ ghi đè Object.Equals() là gì?

Phương pháp này xác định sự bình đẳng của sử dụng comparer bình đẳng mặc định, theo định nghĩa của thực hiện của đối tượng của phương pháp IEquatable.Equals cho T (loại giá trị trong danh sách).

Vì vậy, câu hỏi tiếp theo của tôi là: các chức năng/lớp của khuôn khổ .NET sử dụng Object.Equals()? Tôi có nên sử dụng nó ngay từ đầu không?

+2

Giải thích rất tốt ở đây http://blogs.msdn.com/b/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object- s-equals-and-gethashcode.aspx – nawfal

+1

@nawfal: đã được đề cập đến trong câu trả lời được chấp nhận. –

+0

có thể trùng lặp của [Hiểu IEquatable] (http://stackoverflow.com/questions/411500/understanding-iequatable) – nawfal

Trả lời

140

Lý do chính là hiệu suất. Khi generics được giới thiệu trong .NET 2.0, chúng có thể thêm một loạt các lớp gọn gàng như List<T>, Dictionary<K,V>, HashSet<T>, vv. Các cấu trúc này sử dụng rất nhiều GetHashCodeEquals. Nhưng đối với các loại giá trị này yêu cầu boxing. IEquatable<T> cho phép cấu trúc triển khai phương pháp Equals được nhập mạnh mẽ, do đó không yêu cầu quyền anh. Vì vậy, hiệu suất tốt hơn nhiều khi sử dụng các loại giá trị với các bộ sưu tập chung chung.

Loại tham chiếu không được hưởng lợi nhiều nhưng triển khai IEquatable<T> không cho phép bạn tránh dàn diễn viên từ System.Object có thể tạo sự khác biệt nếu được gọi là thường xuyên.

Như đã lưu ý trên Jared Parson's blog, bạn vẫn phải triển khai ghi đè đối tượng.

+0

Có phân đoạn nào giữa các loại tham chiếu không? Tôi luôn luôn nghĩ rằng phôi chỉ là "báo cáo" bạn thực hiện cho trình biên dịch khi bạn chỉ định một số phôi không rõ ràng từ một loại đối tượng khác. Đây là, sau khi bạn biên dịch, mã đó thậm chí không biết có một diễn viên ở đó. –

+5

Điều đó đúng trong ngôn ngữ C++ nhưng không phải là ngôn ngữ .NET thực thi an toàn loại. Có một thời gian chạy cast và nếu cast không thành công, một ngoại lệ được ném. Vì vậy, có một hình phạt thời gian chạy nhỏ để trả tiền cho đúc. Trình biên dịch có thể tối ưu hóa upcasts cho ví dụ đối tượng o = (object) "string"; Nhưng downcasting - string s = (string) o; - phải xảy ra khi chạy. – Josh

+1

Tôi hiểu. Tình cờ bạn có bất kỳ nơi nào mà tôi có thể nhận được thông tin "sâu sắc hơn" về .NET? Cảm ơn! –

34

Theo MSDN:

Nếu bạn thực hiện IEquatable(T), bạn cũng nên ghi đè lên các lớp cơ sở triển khai của Object.Equals(Object)GetHashCode để hành vi của họ là phù hợp với điều đó của phương pháp IEquatable(T).Equals . Nếu bạn ghi đè Object.Equals(Object), việc thực hiện bị ghi đè của bạn cũng được gọi trong các cuộc gọi vào phương thức tĩnh Equals(System.Object, System.Object) trên lớp học của bạn. Điều này đảm bảo rằng tất cả các yêu cầu của phương thức trả lại Equals nhất quán là kết quả.

Vì vậy, có vẻ như không có sự khác biệt chức năng thực sự giữa hai ngoại trừ việc có thể được gọi tùy thuộc vào cách lớp được sử dụng. Từ quan điểm hiệu suất, tốt hơn là sử dụng phiên bản chung vì không có hình phạt quyền anh/unboxing nào liên quan đến nó.

Từ quan điểm logic, tốt hơn là triển khai giao diện. Việc ghi đè đối tượng không thực sự cho bất kỳ ai biết rằng lớp của bạn thực sự tương đương. Ghi đè có thể chỉ là một lớp không làm gì hoặc triển khai nông. Sử dụng giao diện một cách rõ ràng nói, "Này, điều này là hợp lệ để kiểm tra bình đẳng!" Nó chỉ là thiết kế tốt hơn.

+0

Vâng, chúng đều là điểm tốt. –

+4

Các cấu trúc chắc chắn nên triển khai iEquatable (của theirOwnType) nếu chúng sẽ được sử dụng như các khóa trong từ điển hoặc bộ sưu tập tương tự; nó sẽ cung cấp một tăng hiệu suất lớn. Các lớp không kế thừa sẽ nhận được một tăng hiệu suất nhỏ bằng cách triển khai IEquatable (của theirOwnType). Các lớp kế thừa nên // không // thực hiện IEquatable. – supercat

19

Mở rộng những gì Josh đã nói với ví dụ thực tế.1 to Josh - Tôi sắp viết như vậy trong câu trả lời của mình.

public abstract class EntityBase : IEquatable<EntityBase> 
{ 
    public EntityBase() { } 

    #region IEquatable<EntityBase> Members 

    public bool Equals(EntityBase other) 
    { 
     //Generic implementation of equality using reflection on derived class instance. 
     return true; 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as EntityBase); 
    } 

    #endregion 
} 

public class Author : EntityBase 
{ 
    public Author() { } 
} 

public class Book : EntityBase 
{ 
    public Book() { } 
} 

Bằng cách này, tôi có thể sử dụng lại phương thức Equals() cho tất cả các lớp học có nguồn gốc của tôi.

+0

Chỉ còn một câu hỏi nữa. Lợi thế của việc sử dụng "obj as EntityBase" thay vì (EntityBase) obj là gì? Chỉ là vấn đề về phong cách hoặc có lợi thế gì không? –

+15

trong trường hợp "obj as EntityBase" - nếu obj không thuộc loại EntityBase, nó sẽ vượt qua "null" và tiếp tục mà không có bất kỳ lỗi hoặc ngoại lệ nào, nhưng trong trường hợp "EntityBase) obj", nó sẽ cố gắng truyền obj để EntityBase và nếu obj không phải là loại EntityBase, nó sẽ ném InvalidCastException. Và có, "như" chỉ có thể được áp dụng cho các loại tham chiếu. –

+0

Ah, tôi hiểu rồi. Tuyệt quá. Cảm ơn! –

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