Sự khác biệt giữa IEquitable và chỉ ghi đè Object.Equals () là gì?


183

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

Phương thức này xác định đẳng thức bằng cách sử dụng trình so sánh đẳng thức mặc định, như được xác định bởi việc thực hiện phương thức IEquitable.Equals của đối tượng 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 nào của .NET framework sử dụng Object.Equals()? Tôi có nên sử dụng nó ở nơi đầu tiên?


3
Một lời giải thích rất tốt ở đây blogs.msdn.com/b/jaredpar/archive/2009/01/15/...
nawfal

bản sao có thể có của Hiểu
IEquitable

Câu trả lời:


213

Lý do chính là hiệu suất. Khi Generics đã được giới thiệu trong .NET 2.0 họ đã có thể để thêm một loạt các lớp học gọn gàng như List<T>, Dictionary<K,V>, HashSet<T>, vv Những công trình sử dụng nhiều của GetHashCodeEquals. Nhưng đối với các loại giá trị này yêu cầu quyền anh. IEquatable<T>cho phép một cấu trúc thực hiện một Equalsphương pháp gõ mạnh để không cần đấm bốc. Do đó 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.

Các kiểu tham chiếu không mang lại lợi ích nhiều nhưng việc IEquatable<T>triển khai cho phép bạn tránh được một diễn viên System.Objectcó thể tạo ra sự khác biệt nếu nó được gọi thường xuyên.

Như đã lưu ý trên blog của Jared Parson , bạn vẫn phải thực hiện ghi đè Đối tượng.


Có bất kỳ diễn viên giữa các loại tài liệu tham khảo? Tôi luôn nghĩ rằng các phôi chỉ là "câu lệnh" bạn tạo cho trình biên dịch khi bạn gán 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í sẽ không biết có một dàn diễn viên ở đó.
nuốt chửng elysium

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

1
Tôi hiểu rồi. Tình cờ bạn có nơi nào tôi có thể nhận được loại thông tin "sâu hơn" về .NET không? Cảm ơn!
nuốt chửng elysium

7
Tôi muốn giới thiệu CLR thông qua C # của Jeff Richter và C # in Depth của Jon Skeet. Đối với blog, blog Wintellect là tốt, blog msDN, v.v.
Josh

Liệu IEquatable<T>giao diện làm bất cứ điều gì hơn nhắc nhở một nhà phát triển để bao gồm một public bool Equals(T other) thành viên trong lớp hoặc struct? Sự hiện diện hay vắng mặt của giao diện không tạo ra sự khác biệt trong thời gian chạy. Sự quá tải Equalssẽ xuất hiện là tất cả những gì cần thiết.
mikemay

47

Theo MSDN :

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

Vì vậy, có vẻ như không có sự khác biệt về chức năng thực sự giữa hai loại trừ việc có thể được gọi tùy thuộc vào cách sử dụng lớp. 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 đấm bốc / bỏ hộp liên quan đến nó.

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


9
Các cấu trúc chắc chắn nên triển khai iEquitable (trong sốOwnType) của chúng nếu chúng sẽ được sử dụng làm 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 sự tăng hiệu suất nhẹ bằng cách triển khai IEquitable (của themOwnType). Các lớp kế thừa nên // không // thực hiện IEquitable.
supercat

30

Mở rộng những gì Josh nói với một ví dụ thực tế. +1 cho Josh - Tôi sắp viết tương tự 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ó phương thức Equals () có thể sử dụng lại hoạt động ngoài hộp cho tất cả các lớp dẫn xuất của tôi.


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

22
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 sử dụng obj " vào EntityBase và nếu obj không phải là kiểu EntityBase, nó sẽ ném UnlimitedCastException. Và có, "như" chỉ có thể được áp dụng cho các loại tham chiếu.
cái này __cpered_geek

1
Liên kết của Josh đến blog của Jared Par dường như đề nghị bạn cũng cần ghi đè GetHashCode. đây không phải là trường hợp?
Amitable

3
Tôi không thực sự nhận được giá trị bổ sung mà việc triển khai của bạn cung cấp. Bạn có thể làm rõ vấn đề mà lớp cơ sở trừu tượng của bạn giải quyết?
Mert Akcakaya

1
@Amossible - có, bất cứ khi nào bạn ghi đè Object.Equals (Object), bạn cũng phải ghi đè GetHashCode để các container hoạt động.
namford

0

Nếu chúng ta gọi object.Equals, nó buộc phải đóng hộp đắt tiền về các loại giá trị. Điều này là không mong muốn trong các kịch bản nhạy cảm hiệu suất. Giải pháp là sử dụng IEquatable<T>.

public interface IEquatable<T>
{
  bool Equals (T other);
}

Ý tưởng đằng sau IEquatable<T>là nó cho kết quả tương tự object.Equalsnhưng nhanh hơn. Các ràng buộc where T : IEquatable<T>phải được sử dụng với các loại chung chung như dưới đây.

public class Test<T> where T : IEquatable<T>
{
  public bool IsEqual (T a, T b)
  {
    return a.Equals (b); // No boxing with generic T
  }
}

mặt khác, nó liên kết với slower object.Equals().

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.