Saya ingin memahami skenario di mana IEqualityComparer<T>
dan IEquatable<T>
harus digunakan. Dokumentasi MSDN untuk keduanya terlihat sangat mirip.
151
Saya ingin memahami skenario di mana IEqualityComparer<T>
dan IEquatable<T>
harus digunakan. Dokumentasi MSDN untuk keduanya terlihat sangat mirip.
EqualityComparer<T>
alih-alih mengimplementasikan antarmuka "karenaEqualityComparer<T>
menguji kesetaraan menggunakanIEquatable<T>
T
penerapan apa punIEquatable<T>
. Apakah koleksi inginList<T>
memiliki semacam bug halus di dalamnya?Jawaban:
IEqualityComparer<T>
adalah antarmuka untuk objek yang melakukan perbandingan pada dua objek jenisT
.IEquatable<T>
adalah untuk objek bertipeT
sehingga dapat membandingkan dirinya dengan yang lain dari jenis yang sama.sumber
IEqualityComparer<T>
adalah sebuah antarmuka untuk suatu objek (yang biasanya kelas yang berbeda ringan dariT
) yang menyediakan fungsi perbandingan yang beroperasi diT
Ketika memutuskan apakah akan menggunakan
IEquatable<T>
atauIEqualityComparer<T>
, orang bisa bertanya:Jika hanya ada satu cara menguji dua contoh
T
untuk kesetaraan, atau jika salah satu dari beberapa metode lebih disukai, makaIEquatable<T>
akan menjadi pilihan yang tepat: Antarmuka ini seharusnya dilaksanakan hanya denganT
sendirinya, sehingga satu contohT
memiliki pengetahuan internal tentang bagaimana membandingkan dirinya dengan contoh lain dariT
.Di sisi lain, jika ada beberapa metode yang sama-sama masuk akal membandingkan dua
T
untuk kesetaraan,IEqualityComparer<T>
akan tampak lebih tepat: Antarmuka ini tidak dimaksudkan untuk diimplementasikan denganT
sendirinya, tetapi oleh kelas "eksternal" lainnya. Oleh karena itu, ketika menguji dua contohT
untuk kesetaraan, karenaT
tidak memiliki pemahaman internal tentang kesetaraan, Anda harus membuat pilihan eksplisit dariIEqualityComparer<T>
contoh yang melakukan pengujian sesuai dengan persyaratan spesifik Anda.Contoh:
Mari kita pertimbangkan dua jenis ini (yang seharusnya memiliki semantik nilai ):
Mengapa hanya salah satu dari jenis ini yang mewarisi
IEquatable<>
, tetapi tidak yang lain?Secara teori, hanya ada satu cara yang masuk akal untuk membandingkan dua contoh dari kedua jenis: Mereka sama jika
X
danY
properti di kedua contoh sama. Menurut pemikiran ini, kedua jenis harus diterapkanIEquatable<>
, karena tampaknya tidak ada cara lain yang berarti untuk melakukan tes kesetaraan.Masalahnya di sini adalah bahwa membandingkan angka floating-point untuk kesetaraan mungkin tidak berfungsi seperti yang diharapkan, karena kesalahan pembulatan menit . Ada beberapa metode yang berbeda untuk membandingkan angka floating-point untuk hampir-kesetaraan , masing-masing dengan keunggulan dan pengorbanan tertentu, dan Anda mungkin ingin dapat memilih sendiri metode mana yang tepat.
Perhatikan bahwa halaman yang saya tautkan (di atas) secara eksplisit menyatakan bahwa tes untuk hampir-kesetaraan ini memiliki beberapa kelemahan. Karena ini adalah
IEqualityComparer<T>
implementasi, Anda bisa menukar saja jika itu tidak cukup baik untuk tujuan Anda.sumber
IEqualityComparer<T>
implementasi yang sah harus menerapkan hubungan ekivalensi, yang menyiratkan bahwa dalam semua kasus di mana dua objek membandingkan sama dengan ketiga, mereka harus membandingkan sama satu sama lain. Setiap kelas yang mengimplementasikanIEquatable<T>
atauIEqualityComparer<T>
dengan cara yang bertentangan dengan di atas rusak.IEqualityComparer<String>
yang menganggap "halo" sama dengan "Halo" dan "hElLo" harus menganggap "Halo" dan "hElLo" sama satu sama lain, tetapi untuk sebagian besar metode perbandingan yang tidak akan menjadi masalah.GetHashCode
seharusnya Anda dapat dengan cepat menentukan apakah dua nilai berbeda. Aturannya kira-kira sebagai berikut: (1)GetHashCode
harus selalu menghasilkan kode hash yang sama untuk nilai yang sama. (2)GetHashCode
harus cepat (lebih cepat dariEquals
). (3)GetHashCode
tidak harus tepat (tidak setepatEquals
). Ini berarti dapat menghasilkan kode hash yang sama untuk nilai yang berbeda. Semakin tepat Anda dapat membuatnya, semakin baik, tetapi mungkin lebih penting untuk membuatnya cepat.Anda sudah mendapatkan definisi dasar tentang apa itu . Singkatnya, jika Anda menerapkan
IEquatable<T>
pada kelasT
,Equals
metode pada objek bertipeT
memberitahu Anda jika objek itu sendiri (yang sedang diuji untuk kesetaraan) sama dengan contoh lain dari jenis yang samaT
. Sedangkan,IEqualityComparer<T>
adalah untuk menguji kesetaraan dua contohT
, biasanya di luar lingkup contohT
.Untuk apa mereka bisa membingungkan pada awalnya. Dari definisi itu harus jelas bahwa karenanya
IEquatable<T>
(didefinisikan dalam kelasT
itu sendiri) harus menjadi standar de facto untuk mewakili keunikan objek / instansnya.HashSet<T>
,Dictionary<T, U>
(MengingatGetHashCode
ditimpa juga),Contains
diList<T>
dll make penggunaan ini. MelaksanakanIEqualityComparer<T>
padaT
tidak membantu kasus-kasus umum yang disebutkan di atas. Selanjutnya, ada sedikit nilai untuk diterapkanIEquatable<T>
pada kelas lain selainT
. Ini:jarang masuk akal.
Di samping itu
adalah bagaimana hal itu harus dilakukan.
IEqualityComparer<T>
dapat bermanfaat saat Anda memerlukan validasi khusus kesetaraan, tetapi tidak sebagai aturan umum. Misalnya, dalam kelasPerson
di beberapa titik Anda mungkin perlu menguji kesetaraan dua orang berdasarkan usia mereka. Dalam hal ini Anda dapat melakukan:Untuk mengujinya, coba
Demikian pula
IEqualityComparer<T>
padaT
tidak masuk akal.Benar ini bekerja, tetapi tidak terlihat baik di mata dan mengalahkan logika.
Biasanya yang Anda butuhkan adalah
IEquatable<T>
. Idealnya, Anda hanya dapat memiliki satuIEquatable<T>
sementara beberapaIEqualityComparer<T>
dimungkinkan berdasarkan kriteria yang berbeda.Itu
IEqualityComparer<T>
danIEquatable<T>
persis analog denganComparer<T>
danIComparable<T>
yang digunakan untuk tujuan perbandingan daripada menyamakan; thread yang bagus di sini di mana saya menulis jawaban yang sama :)sumber
public int GetHashCode(Person obj)
harus kembaliobj.GetHashCode()
obj.Age.GetHashCode
. akan diedit.person.GetHashCode
mana saja .... mengapa Anda menimpanya? - Kami mengesampingkan karena intinyaIEqualityComparer
adalah untuk memiliki implementasi perbandingan yang berbeda sesuai dengan aturan kami - aturan yang kami ketahui dengan baik.Age
properti, jadi saya meneleponAge.GetHashCode
. Umur adalah tipeint
, tetapi apa pun jenisnya adalah kontrak kode hash di .NET adalah itudifferent objects can have equal hash but equal objects cant ever have different hashes
. Ini adalah kontrak yang bisa kita percayai secara membuta. Tentu pembanding khusus kami harus mematuhi aturan ini juga. Jika pernah memanggilsomeObject.GetHashCode
hal-hal istirahat, maka itu adalah masalah dengan implementor tipesomeObject
, itu bukan masalah kita.IEqualityComparer adalah untuk digunakan ketika kesetaraan dua objek diimplementasikan secara eksternal, misalnya jika Anda ingin mendefinisikan pembanding untuk dua jenis yang Anda tidak memiliki sumbernya, atau untuk kasus di mana kesetaraan antara dua hal hanya masuk akal dalam konteks terbatas.
IEquatable adalah untuk mengimplementasikan objek itu sendiri (yang dibandingkan untuk kesetaraan).
sumber
Satu membandingkan dua
T
. Yang lain dapat membandingkan dirinya dengan yang lainT
. Biasanya, Anda hanya perlu menggunakannya satu per satu, bukan keduanya.sumber