Apakah antarmuka IComparable sudah usang / "berbahaya"?

11

IComparable hanya bekerja satu arah

Katakanlah Anda memiliki Employeekelas. Dalam satu tampilan, Anda ingin menampilkan semua yang Employeesdiurutkan berdasarkan nama - di tampilan lain, berdasarkan alamat. Bagaimana Anda akan mencapai itu? Tidak dengan IComparable, setidaknya tidak dengan cara idiomatis.

IComparable memiliki logika di tempat yang salah

Antarmuka digunakan dengan memanggil .Sort(). Dalam tampilan yang menunjukkan Customerdiurutkan berdasarkan nama, tidak ada kode sama sekali untuk mengimplikasikan bagaimana kode itu akan diurutkan.
Di sisi lain, Customerkelas mengasumsikan bagaimana akan digunakan - dalam hal ini, bahwa kelas akan digunakan dalam daftar yang diurutkan berdasarkan nama.

IComparable digunakan secara implisit

Dibandingkan dengan alternatif, sangat sulit untuk melihat di mana logika perbandingan digunakan - atau jika sama sekali. Dengan asumsi IDE standar Anda dan mulai dari Customerkelas, saya harus

  1. Cari semua referensi Customer
  2. Temukan referensi yang digunakan dalam daftar
  3. Periksa apakah daftar itu pernah .Sort()memanggil mereka

Yang mungkin lebih buruk, jika Anda menghapus IComparableimplementasi yang masih digunakan, Anda tidak mendapatkan kesalahan atau peringatan. Satu-satunya hal yang akan Anda dapatkan adalah perilaku yang salah di semua tempat yang terlalu tidak jelas untuk Anda pikirkan.

Masalah-masalah ini digabungkan, ditambah perubahan persyaratan

Alasan saya berpikir tentang ini adalah karena itu salah bagi saya. Saya telah dengan senang hati menggunakan IComparableaplikasi saya selama 2 tahun sekarang. Sekarang, persyaratannya berubah dan masalahnya perlu disortir dalam 2 cara berbeda. Telah memperhatikan bahwa tidak menyenangkan melalui langkah-langkah yang dijelaskan di bagian sebelumnya.

Pertanyaan

Masalah-masalah ini membuat saya berpikir IComparablelebih rendah daripada ICompareratau .OrderBy(), sampai tidak melihat adanya use case yang valid yang tidak akan dilayani dengan lebih baik oleh alternatif.
Apakah selalu lebih baik menggunakan ICompareratau LINQ, atau adakah keuntungan / kasus penggunaan yang tidak saya lihat di sini?

R. Schmitz
sumber
2
Persyaratan "macam dua cara" baru Anda adalah ikan herring merah. Untuk mengatasinya, yang harus Anda lakukan adalah memberikan komparator berbeda ke fungsi sortir Anda.
Robert Harvey
@RobertHarvey Maka Anda tidak akan menggunakan IComparablelagi, yang memperkuat poin saya.
R. Schmitz
Jangan lupa bahwa jika Anda menggunakan SortedXXXkoleksi, mereka memerlukan elemen yang disimpan IComparableatau IComparerdisediakan. Juga perhatikan, bahwa itu sepele untuk membalik urutan urutan alami dengan satu pembanding dan membuatnya bekerja dengan semua IComparableobjek.
Berin Loritsch
2
Tidak masalah bahwa ada dua antarmuka yang berbeda. IComparabledianggap sebagai mekanisme perbandingan standar . IComparerdigunakan ketika Anda ingin mengganti mekanisme perbandingan default.
Robert Harvey
Contoh ReverseComparer<T>: gist.github.com/jackfarrington/078e7af7bc82482aa634
Berin Loritsch

Jawaban:

14

IComparablememiliki batasan yang Anda sebutkan, itu benar. Ini adalah antarmuka yang sudah tersedia di .NET framework 1.0, di mana alternatif fungsional dan Linq tidak tersedia. Jadi ya, orang mungkin melihatnya sebagai elemen kerangka kerja usang yang terutama disimpan untuk kompatibilitas mundur.

Namun, untuk banyak struktur data sederhana, satu cara penyortiran mungkin cukup atau alami. Untuk kasus ini, memiliki satu tempat kanonik untuk menerapkan hubungan pesanan masih merupakan cara yang baik untuk menjaga kode KERING, alih-alih selalu mengulangi logika yang sama dalam setiap panggilan ke OrderBysemua tempat.

Anda telah "dengan senang hati menggunakan IComparable dalam aplikasi Anda selama 2 tahun sekarang", seperti yang Anda tulis, jadi bagi saya sepertinya ini sangat membantu Anda untuk waktu yang lama. Saat Anda sekarang harus memvalidasi, mengubah, dan menguji semua panggilan Sort, itu mungkin juga merupakan tanda Anda melakukan jenis logika penyortiran yang sama di banyak tempat, yang bukan merupakan kesalahan IComparable. Jadi ini bisa menjadi kesempatan untuk lebih memusatkan logika ini di satu tempat, membuat kode Anda lebih KERING.

Doc Brown
sumber
Poin bagus tentang struktur data sederhana. Namun, paragraf terakhir tidak masuk akal bagi saya. Jika saya tidak menggunakan IComparable, semua kode sortir yang sudah ada sebelumnya akan tersentuh dalam pandangan masing-masing, sementara saya hanya akan menambahkan kode sortir baru untuk tampilan baru.
R. Schmitz
@ R.Schmitz Akankah jenis yang sudah ada bekerja dengan benar tanpa IComparableimplementasi yang Anda tulis?
Robert Harvey
3
@ R.Schmitz: Tentu, tapi sekarang Anda berkomitmen untuk selalu memberikan komparator (kecuali jika Anda menggunakan OrderBy, tentu saja). Dengan IComparable, Anda mendapatkan implementasi default secara gratis, dan kadang-kadang Anda bahkan tidak perlu menulis implementasi itu.
Robert Harvey
2
@ R.Schmitz: Komentar terakhir Anda di sana meringkas poinnya dengan baik. Saya akan pergi sedikit lebih jauh. Misalkan Anda memiliki tipe numerik seperti BigInteger. Jika tidak mengimplementasikan operator perbandingan / antarmuka, bagaimana Anda bahkan dapat mengimplementasikan IComparer sendiri ? Anda memerlukan akses ke struktur data internal untuk melakukannya secara efisien, atau sama sekali. Misalkan Anda memiliki tipe seperti Pelanggan; sifat masyarakat yang ingin mengurutkan do memiliki comparers. Bagi saya itulah bedanya: implement IComparable<T>jika tidak masuk akal untuk mengharapkan penelepon mengimplementasikan komparator.
Eric Lippert
1
If I hadn't used IComparable, all the pre-existing sorting code would have been left untouched in their respective views, while I'd only add new sorting code for the new view.Hanya karena IComparablemerupakan solusi yang lebih baik pada saat itu , tidak berarti itu adalah solusi terbaik saat ini . Komentar pertama Anda di sini menyiratkan bahwa "tidak bisa dibandingkan atau tidak sama sekali", yang tidak benar, masalahnya bisa diselesaikan dengan berbagai cara. Aplikasi dapat tumbuh dalam ukuran / skala, dan hal-hal yang dulunya cocok mungkin tidak dapat mengikuti permintaan aplikasi yang semakin meningkat.
Flater
1

Saya setuju dengan sentimen Anda tentang IComparable

Lihat saja komentarnya Array.Sort()

  • Setiap elemen array harus mengimplementasikan IComparableantarmuka agar dapat dibandingkan dengan setiap elemen lainnya dalam array. (atau pengecualian dilemparkan)
  • Jika pengurutan tidak berhasil diselesaikan, hasilnya tidak ditentukan.

Kami mungkin tidak akan pernah sekarang memotivasi, Namun! pertimbangkan object.Equals()metode pada setiap objek yang memungkinkan Anda membandingkan objek satu sama lain untuk melihat apakah mereka "sama"

Anda sudah memilikinya di sana, tetapi telah ditugaskan untuk menambahkan Array.Sort()yang mungkin ingin Anda tambahkanobject.Compare(object)

Ewan
sumber