Khi nào thì sử dụng ICompABLE <T> Vs. IComparer <T>


101

Tôi đang cố gắng tìm ra giao diện nào trong số những giao diện này mà tôi cần triển khai. Về cơ bản, cả hai đều làm cùng một việc. Khi nào thì tôi sử dụng cái này thay cho cái kia?


Các ví dụ và giải thích tuyệt vời được tìm thấy tại đây: support.microsoft.com/nl-nl/help/320727/…
Ngày

Câu trả lời:


96

Chúng không hoàn toàn giống như IComparer<T>được triển khai trên một kiểu có khả năng so sánh hai đối tượng khác nhau trong khi IComparable<T>được triển khai trên các kiểu có thể tự so sánh với các thể hiện khác cùng loại.

Tôi có xu hướng sử dụng IComparable<T>cho những lúc tôi cần biết cách liên quan đến thisphiên bản khác. IComparer<T>rất hữu ích cho việc sắp xếp các bộ sưu tập như là giá trị IComparer<T>đứng ngoài so sánh.


9
IComparer <T> cũng cho phép bạn có một lớp cho mỗi kiểu sắp xếp mà bạn muốn. Thí dụ; PersonLastFirstNameComparer, PersonFirstLastNameComparer, hoặc PersonAgeComparer.
Eric Schneider

Có cách nào dễ dàng bạn sử dụng để ghi nhớ chúng không? Tôi có xu hướng phải tra cứu nó mỗi lần.
amadib

59
@amadib nghĩ IComparablenhư tôi có thể so sánh . có nghĩa là tôi có thể được so sánh với một cái gì đó khác. Và hãy đọc IComparerkhi tôi là người so sánh, tôi chỉ đơn giản so sánh nghĩa là tôi so sánh một số thứ.
nawfal

@newfal Bạn nên đặt điều này như một câu trả lời. Tôi nghĩ rằng đó là lời giải thích tốt nhất ở đây.
Gene S

42

Sử dụng IComparable<T>khi lớp có một so sánh nội tại.

Sử dụng IComparer<T>khi bạn muốn một phương thức so sánh khác với phương thức so sánh nội tại của lớp, nếu nó có một phương thức so sánh.


28

Nó phụ thuộc vào thực thể. Ví dụ sau đây cho một lớp như "Sinh viên", sẽ có ý nghĩa nếu có IComp so sánh dựa trên Tên.

class Student : IComparable 
{
    public string Name { get; set; }
    public int MathScore { get; set; }
    public int EnglishScore { get; set; }

    public int TotalScore 
    {
        get
        {
            return this.MathScore + this.EnglishScore; 
        }
    }

    public int CompareTo(object obj)
    {
        return CompareTo(obj as Student);  
    }

    public int CompareTo(Student other)
    {
        if (other == null)
        {
            return 1;
        }
        return this.Name.CompareTo(other.Name);  
    }
}

Nhưng nếu giáo viên 'A' muốn so sánh học sinh dựa trên MathScore và giáo viên 'B' muốn so sánh học sinh dựa trên EnglishScore. Nó sẽ là một ý tưởng tốt để triển khai IComparer riêng biệt. (Giống một mẫu chiến lược hơn)

class CompareByMathScore : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        if (x.MathScore > y.MathScore)
          return 1;
        if (x.MathScore < y.MathScore)
          return -1;
        else
          return 0;
    }
}

Đặt phương thức Compare là tĩnh để dễ sử dụng.
Ngày

9

Tất cả phụ thuộc vào việc loại của bạn có thể thay đổi được hay không. Bạn chỉ nên triển khai IComp so sánh được trên các loại không thể thay đổi. Lưu ý rằng nếu bạn triển khai IComp so sánh được, bạn phải ghi đè Bằng, cùng với các toán tử ==,! =, <Và> (xem cảnh báo Phân tích mã CA1036).

Trích dẫn Dave G từ bài đăng trên blog này :

Nhưng câu trả lời chính xác là triển khai IComparer thay vì IComp so sánh được nếu các đối tượng của bạn có thể thay đổi được và chuyển một thể hiện của IComparer để sắp xếp các chức năng khi cần thiết.

Vì IComparer chỉ là một đối tượng dùng một lần được sử dụng để phân loại tại thời điểm đó, nên đối tượng của bạn có thể có bất kỳ ngữ nghĩa có thể thay đổi nào mà bạn mong muốn. Hơn nữa, nó không yêu cầu hoặc thậm chí đề xuất sử dụng Equals, GetHashCode hoặc == - bạn có thể tự do xác định nó theo bất kỳ cách nào bạn muốn.

Cuối cùng, bạn có thể xác định nhiều IComparer cho loại của bạn để sắp xếp trên các trường khác nhau hoặc với các quy tắc khác nhau. Điều này linh hoạt hơn nhiều so với việc bị mắc kẹt với một định nghĩa.

Nói tóm lại: Sử dụng ICompABLE cho các loại giá trị và IComparer cho các loại tham chiếu.


6

Giải thích đơn giản qua một câu chuyện

Bóng rổ trung học. Đó là một lựa chọn sân trường cho các đội. Tôi muốn có được những người cao nhất / giỏi nhất / nhanh nhất vào nhóm của mình. Tôi làm gì?

Giao diện IComparer - So sánh hai người tách biệt người

  • Điều này cho phép tôi so sánh bất kỳ hai người đàn ông nào được xếp hàng ......... về cơ bản là vậy. Fred vs John .......... tôi ném chúng vào một lớp cụ thể triển khai giao diện. Compare(Fred, John)và nó chỉ ra ai giỏi hơn.

Điều gì về IComp so sánh được? - So sánh bản thân với người khác

Gần đây bạn có vào FB không? Bạn thấy những người khác đang làm những điều thú vị: đi du lịch khắp thế giới, tạo ra các phát minh, trong khi tôi đang làm một việc không hoàn toàn thú vị - những gì chúng tôi đang làm là sử dụng giao diện có thể so sánh được.

  • Chúng tôi đang so sánh cá thể hiện tại (chính bạn) với một đối tượng khác (người khác) cùng loại (người).

Còn về Class Comparer thì sao?

Lớp Comparer là một lớp cơ sở trừu tượng thực hiện giao diện IComparer. Bạn nên bắt nguồn từ lớp này để có một triển khai cụ thể. Dù sao, Microsoft khuyến nghị bạn NÊN sử dụng lớp So sánh hơn là triển khai giao diện IComparer:

Chúng tôi khuyên bạn nên dẫn xuất từ ​​lớp Comparer thay vì triển khai giao diện IComparer, vì lớp Comparer cung cấp một triển khai giao diện rõ ràng của phương thức IComparer.Compare và thuộc tính Mặc định lấy trình so sánh mặc định cho đối tượng.

Tóm lược

  • IComparer - sắp xếp hai thứ và so sánh.
  • Không thể so sánh được - so sánh bạn với những người khác trên FB.

Mong truyện giúp các bạn nhớ.


1
Tôi thích cách của bạn để minh họa khái niệm chính. Sẽ tốt hơn nếu bạn bao gồm cả lớp So sánh (T) vào cuộc thi này. Thậm chí nó không bao gồm trong câu hỏi. :)
Kevman

4

Như những người khác đã nói, họ không làm điều tương tự.

Trong mọi trường hợp, những ngày này tôi có xu hướng không sử dụng IComparer. Tại sao tôi sẽ? Trách nhiệm của nó (một thực thể bên ngoài được sử dụng để so sánh hai đối tượng) có thể được xử lý gọn gàng hơn nhiều với biểu thức lambda, tương tự như cách hoạt động của hầu hết các phương thức của LINQ. Viết một lambda nhanh chóng lấy các đối tượng để so sánh làm đối số và trả về bool. Và nếu đối tượng xác định hoạt động so sánh nội tại của chính nó, thay vào đó nó có thể thực hiện ICompABLE.


1
-1: trả về bool không tương đương với IComparer. IComparer trả về một giá trị có thể nhỏ hơn 0/0 / lớn hơn 0 và thường được sử dụng để sắp xếp.
Joe

Và khi đó là những gì bạn cần, bạn sẽ trả về một int (hoặc tốt hơn nữa, một enum). Đó thực sự là một vấn đề lớn?
jalf

2
Bạn thậm chí có thể trả về bool, vì ít hơn là thao tác duy nhất bạn cần để sắp xếp một chuỗi.
jalf

việc triển khai IComparer chỉ cần được xác định một lần, nếu bạn cần sử dụng logic sắp xếp ở nhiều nơi hơn, thì biểu thức lambda sẽ cần được viết nhiều lần hơn.
oɔɯǝɹ

oɔɯǝɹ - Sau đó, bạn có thể lưu trữ một tham chiếu đến đại biểu đã được viết dưới dạng biểu thức lambda cũng như sử dụng lại nó.
jpierson

3

ICompABLE nói rằng một đối tượng có thể được so sánh với một đối tượng khác. IComparer là một đối tượng có thể so sánh hai mục bất kỳ.


2

IComparer là một giao diện được sử dụng để sắp xếp Mảng, giao diện này sẽ buộc lớp thực hiện phương thức Compare (T x, T y), phương thức này sẽ so sánh hai đối tượng. Thể hiện của lớp đã triển khai giao diện này được sử dụng trong việc sắp xếp Mảng.

IComp so sánh được là một giao diện được thực hiện theo kiểu cần so sánh hai đối tượng cùng kiểu, Giao diện có thể so sánh này sẽ buộc lớp thực hiện phương thức sau CompareTo (T obj)

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

Bây giờ chúng ta lấy một Ví dụ chúng ta có một lớp Nhân viên, dựa trên lớp này, chúng ta phải tạo một Bộ sưu tập. Bây giờ chúng tôi có các yêu cầu sau.

Sắp xếp mảng bằng cách sử dụng lớp Mảng 2. Cần một bộ sưu tập bằng Linq: Loại bỏ trùng lặp, Thứ tự cao hơn đến thấp hơn, Xóa một id nhân viên

abstract public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { set; get; }
}

public enum SortType
{
    ByID,
    BySalary
}

public class EmployeeIdSorter: IComparer {public int Compare (Employee x, Employee y) {if (x.Id <y.Id) return 1; else if (x.Id> y.Id) return -1; khác trả về 0; }}

    public class EmployeeSalarySorter : IComparer<Employee>
    {
        public int Compare(Employee x, Employee y)
        {
            if (x.Salary < y.Salary)
                return 1;
            else if (x.Salary > y.Salary)
                return -1;
            else
                return 0;
        }
    }

Để biết thêm thông tin, hãy tham khảo bên dưới http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomporing-and.html

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.