Kapan menggunakan IComparable <T> Vs. IComparer <T>

Jawaban:

96

Mereka tidak persis sama seperti IComparer<T>yang diimplementasikan pada tipe yang mampu membandingkan dua objek yang berbeda saat IComparable<T>diimplementasikan pada tipe yang mampu membandingkan dirinya dengan contoh lain dari tipe yang sama.

Saya cenderung menggunakan IComparable<T>saat-saat ketika saya perlu tahu bagaimana instance lain berhubungan dengan thisinstance. IComparer<T>berguna untuk menyortir koleksi sebagai IComparer<T>stand di luar perbandingan.

Andrew Hare
sumber
9
IComparer <T> juga memungkinkan Anda memiliki kelas untuk setiap jenis pengurutan yang Anda inginkan. Contoh; PersonLastFirstNameComparer, PersonFirstLastNameComparer, atau PersonAgeComparer.
Eric Schneider
Apakah ada cara mudah yang Anda gunakan untuk mengingatnya? Saya cenderung harus mencarinya setiap kali.
amadib
59
@amadib berpikir IComparableseperti saya sebanding . yang berarti saya bisa dibandingkan dengan sesuatu yang lain. Dan membaca IComparerkarena saya seorang pembanding, saya hanya membandingkan yang berarti saya membandingkan beberapa hal.
nawfal
@newfal Anda harus menempatkan ini sebagai jawaban. Saya pikir itu adalah penjelasan terbaik di sini.
Gene S
42

Gunakan IComparable<T>jika kelas memiliki perbandingan intrinsik.

Gunakan IComparer<T>jika Anda menginginkan metode perbandingan selain perbandingan intrinsik kelas, jika ada.

yfeldblum
sumber
28

Itu tergantung pada entitasnya. Sebagai contoh mengikuti kelas seperti "Mahasiswa", akan masuk akal untuk memiliki IComparable berdasarkan Name.

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);  
    }
}

Tetapi jika guru 'A' ingin membandingkan siswa berdasarkan MathScore, dan guru 'B' ingin membandingkan siswa berdasarkan EnglishScore. Ide bagus untuk mengimplementasikan IComparer secara terpisah. (Lebih mirip pola strategi)

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;
    }
}
Ajay Bhosale
sumber
Jadikan metode Bandingkan statis agar mudah digunakan.
Jan
9

Itu semua tergantung pada apakah tipe Anda bisa berubah atau tidak. Anda sebaiknya hanya mengimplementasikan IComparable pada tipe yang tidak bisa berubah. Perhatikan bahwa jika Anda mengimplementasikan IComparable, Anda harus mengganti Sama, bersama dengan operator ==,! =, <Dan> (lihat peringatan Analisis Kode CA1036).

Mengutip Dave G dari postingan blog ini :

Tetapi jawaban yang benar adalah dengan mengimplementasikan IComparer alih-alih IComparable jika objek Anda bisa berubah, dan meneruskan instance IComparer ke fungsi pengurutan jika diperlukan.

Karena IComparer hanyalah objek sekali pakai yang digunakan untuk menyortir pada saat itu, objek Anda dapat memiliki semantik yang dapat berubah sesuai keinginan Anda. Selain itu, tidak memerlukan atau bahkan menyarankan penggunaan Equals, GetHashCode, atau == - Anda bebas untuk mendefinisikannya sesuka Anda.

Terakhir, Anda dapat menentukan beberapa IComparer untuk jenis Anda untuk menyortir pada bidang berbeda atau dengan aturan berbeda. Ini jauh lebih fleksibel daripada terpaku pada satu definisi.

Singkatnya: Gunakan IComparable untuk tipe nilai dan IComparer untuk tipe referensi.

Tuan Bungle
sumber
6

Penjelasan Sederhana melalui sebuah cerita

Bola basket sekolah menengah. Ini adalah pilihan halaman sekolah untuk tim. Saya ingin mendapatkan orang tertinggi / terbaik / tercepat di tim saya. Apa yang saya lakukan?

IComparer Interface - Bandingkan dua orang yang terpisah

  • Hal ini memungkinkan saya untuk membandingkan dua orang yang berbaris ......... pada dasarnya itu. Fred vs John .......... saya memasukkannya ke dalam kelas konkret yang mengimplementasikan antarmuka. Compare(Fred, John)dan itu memuntahkan siapa yang lebih baik.

Bagaimana dengan IComparable? - Bandingkan diri Anda dengan orang lain

Apakah Anda pernah menggunakan FB baru-baru ini? Anda melihat orang lain melakukan hal-hal keren: berkeliling dunia, membuat penemuan, sementara saya melakukan sesuatu yang tidak terlalu keren - yang kami lakukan adalah memanfaatkan antarmuka IComparable.

  • Kami membandingkan contoh saat ini (diri Anda sendiri) dengan objek lain (orang lain) yang memiliki tipe yang sama (orang).

Bagaimana dengan Kelas Pembanding?

Kelas Comparer adalah kelas dasar abstrak yang mengimplementasikan antarmuka IComparer. Anda harus turun dari kelas ini untuk mendapatkan implementasi yang konkret. bagaimanapun, Microsoft menganjurkan agar Anda DO menggunakan kelas Comparer daripada mengimplementasikan antarmuka IComparer:

Kami merekomendasikan agar Anda mendapatkan dari kelas Comparer daripada mengimplementasikan antarmuka IComparer, karena kelas Comparer menyediakan implementasi antarmuka eksplisit dari metode IComparer.Compare dan properti Default yang mendapatkan pembanding default untuk objek.

Ringkasan

  • IComparer - sejajarkan dua hal dan bandingkan.
  • IComparable - bandingkan diri Anda dengan orang lain di FB.

Semoga ceritanya membantu Anda mengingat.

BKSpurgeon
sumber
1
Saya suka cara Anda mengilustrasikan konsep kunci. Akan lebih baik jika Anda memasukkan kelas Pembanding (T) ke dalam kontes ini. Bahkan itu tidak termasuk dalam pertanyaan tersebut. :)
Kevman
4

Seperti yang dikatakan orang lain, mereka tidak melakukan hal yang sama.

Bagaimanapun, hari ini saya cenderung tidak menggunakan IComparer. Mengapa saya harus? Tanggung jawabnya (entitas eksternal yang digunakan untuk membandingkan dua objek) dapat ditangani lebih bersih dengan ekspresi lambda, mirip dengan cara kerja sebagian besar metode LINQ. Tulis lambda cepat yang mengambil objek untuk dibandingkan sebagai argumen, dan mengembalikan bool. Dan jika objek mendefinisikan operasi perbandingan intrinsiknya sendiri, ia dapat mengimplementasikan IComparable sebagai gantinya.

jalf
sumber
1
-1: mengembalikan bool tidak sama dengan IComparer. IComparer mengembalikan nilai yang bisa kurang dari nol / nol / lebih besar dari nol dan biasanya digunakan untuk pengurutan.
Joe
Dan bila itu yang Anda butuhkan, Anda mengembalikan int (atau lebih baik lagi, enum) sebagai gantinya. Apakah itu masalah besar?
jalf
2
Anda bahkan dapat mengembalikan bool, karena kurang dari satu-satunya operasi yang Anda perlukan untuk mengurutkan urutan.
jalf
implementasi IComparer hanya perlu didefinisikan sekali, jika Anda perlu menggunakan logika pengurutan di lebih banyak tempat, ekspresi lambda perlu ditulis lebih banyak.
oɔɯǝɹ
oɔɯǝɹ - Kemudian Anda dapat menyimpan referensi ke delegasi yang ditulis sebagai ekspresi lambda yang juga digunakan kembali.
jpierson
3

IComparable mengatakan suatu objek dapat dibandingkan dengan yang lain. IComparer adalah objek yang dapat membandingkan dua item.

Neil Barnwell
sumber
2

IComparer adalah antarmuka yang digunakan untuk mengurutkan Array, antarmuka ini akan memaksa kelas untuk mengimplementasikan metode Compare (T x, T y), yang akan membandingkan kedua objek tersebut. Instance dari kelas yang mengimplementasikan antarmuka ini digunakan dalam pengurutan Array.

IComparable adalah antarmuka yang diimplementasikan dalam tipe yang perlu membandingkan dua objek dari tipe yang sama, Antarmuka yang sebanding ini akan memaksa kelas untuk mengimplementasikan metode berikut CompareTo (T obj)

IEqualityComparer adalah antarmuka yang digunakan untuk menemukan objek apakah itu Sama atau tidak, Sekarang kita akan melihat ini dalam contoh di mana kita harus menemukan Perbedaan Objek dalam koleksi. Antarmuka ini akan mengimplementasikan metode Equals (T obj1, T obj2)

Sekarang kita ambil Contoh kita memiliki kelas Karyawan, berdasarkan kelas ini kita harus membuat Koleksi. Sekarang kami memiliki persyaratan berikut.

Sortir Array menggunakan Array class 2. Perlu koleksi menggunakan Linq: Hapus Duplikat, Urutkan dari atas ke bawah, Hapus satu id karyawan

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 Bandingkan (Karyawan x, Karyawan y) {if (x.Id <y.Id) return 1; else if (x.Id> y.Id) return -1; lain kembali 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;
        }
    }

Untuk info lebih lanjut lihat di bawah ini http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

Rajesh G
sumber