Sudah lama sekali, namun menurut saya masih perlu memberikan jawaban yang benar atas pertanyaan ini, termasuk penjelasan tentang kenapa dan bagaimana. Jawaban terbaik sejauh ini adalah yang mengutip MSDN secara lengkap - jangan mencoba membuat aturan Anda sendiri, orang-orang MS tahu apa yang mereka lakukan.
Tetapi hal pertama yang pertama: Pedoman seperti yang dikutip dalam pertanyaan itu salah.
Sekarang mengapa - ada dua di antaranya
Pertama mengapa : Jika hashcode dihitung dengan cara, itu tidak berubah selama masa pakai objek, bahkan jika objek itu sendiri berubah, daripada itu akan melanggar kontrak yang sama.
Ingat: "Jika dua objek dibandingkan sama, metode GetHashCode untuk setiap objek harus mengembalikan nilai yang sama. Namun, jika dua objek tidak dibandingkan sebagai sama, metode GetHashCode untuk dua objek tidak harus mengembalikan nilai yang berbeda."
Kalimat kedua sering disalahartikan sebagai "Satu-satunya aturan adalah, pada saat pembuatan objek, kode hash dari objek yang sama harus sama". Tidak benar-benar tahu mengapa, tapi itulah inti dari sebagian besar jawaban di sini.
Pikirkan dua objek yang berisi nama, di mana nama tersebut digunakan dalam metode sama dengan: Nama yang sama -> hal yang sama. Buat Instance A: Name = Joe Buat Instance B: Name = Peter
Hashcode A dan Hashcode B kemungkinan besar tidak akan sama. Apa yang sekarang akan terjadi, ketika Nama instance B diubah menjadi Joe?
Menurut pedoman dari pertanyaan, kode hash B tidak akan berubah. Hasilnya akan menjadi: A.Equals (B) ==> true Tetapi pada saat yang sama: A.GetHashCode () == B.GetHashCode () ==> false.
Tapi sebenarnya perilaku ini dilarang secara eksplisit oleh sama & hashcode-contract.
Kedua mengapa : Meskipun - tentu saja - benar, bahwa perubahan dalam kode hash dapat merusak daftar hash dan objek lain yang menggunakan kode hash, kebalikannya juga benar. Tidak mengubah kode hash, dalam kasus terburuk, akan mendapatkan daftar hash, di mana semua banyak objek yang berbeda akan memiliki kode hash yang sama dan karenanya berada dalam bin hash yang sama - terjadi ketika objek diinisialisasi dengan nilai standar, misalnya.
Sekarang datang ke bagaimana Nah, pada pandangan pertama, tampaknya ada kontradiksi - bagaimanapun, kode akan rusak. Tetapi tidak ada masalah yang berasal dari kode hash yang diubah atau tidak berubah.
Sumber masalah dijelaskan dengan baik di MSDN:
Dari entri hashtable MSDN:
Objek kunci harus tidak dapat diubah selama digunakan sebagai kunci di Hashtable.
Artinya:
Objek apa pun yang membuat nilai hash harus mengubah nilai hash, saat objek berubah, tetapi tidak boleh - mutlak tidak boleh - mengizinkan perubahan apa pun pada dirinya sendiri, saat digunakan di dalam Hashtable (atau objek lain yang menggunakan Hash, tentu saja) .
Pertama, cara termudah tentu saja untuk mendesain objek yang tidak dapat diubah hanya untuk digunakan dalam hashtable, yang akan dibuat sebagai salinan dari objek normal yang bisa berubah saat diperlukan. Di dalam objek yang tidak dapat diubah, tidak apa-apa untuk menyimpan kode hash, karena itu tidak dapat diubah.
Kedua bagaimana Atau berikan objek "Anda sedang di-hash sekarang" -bendera, pastikan semua data objek bersifat pribadi, centang bendera di semua fungsi yang dapat mengubah data objek dan melempar data pengecualian jika perubahan tidak diizinkan (yaitu, bendera disetel ). Sekarang, saat Anda meletakkan objek di sembarang area yang di-hash, pastikan untuk menyetel benderanya, dan - juga - hapus setel benderanya, jika sudah tidak diperlukan lagi. Untuk kemudahan penggunaan, saya menyarankan untuk menyetel flag secara otomatis di dalam metode "GetHashCode" - cara ini tidak dapat dilupakan. Dan panggilan eksplisit dari metode "ResetHashFlag" akan memastikan, bahwa programmer harus berpikir, apakah diperbolehkan atau tidak untuk mengubah data objek sekarang.
Ok, apa yang harus dikatakan juga: Ada kasus, di mana dimungkinkan untuk memiliki objek dengan data yang bisa berubah, di mana kode hash tetap tidak berubah, ketika data objek diubah, tanpa melanggar sama & kontrak-kode hash.
Namun ini membutuhkan, bahwa metode yang sama tidak didasarkan pada data yang bisa berubah juga. Jadi, jika saya menulis objek, dan membuat metode GetHashCode yang menghitung nilai hanya sekali dan menyimpannya di dalam objek untuk mengembalikannya pada panggilan berikutnya, maka saya harus, sekali lagi: mutlak harus, membuat metode Equals, yang akan digunakan nilai yang disimpan untuk perbandingan, sehingga A.Equals (B) tidak akan pernah berubah dari salah menjadi benar juga. Jika tidak, kontrak akan diputus. Hasil dari ini biasanya adalah bahwa metode Sama dengan tidak masuk akal - ini bukan referensi asli yang sama, tetapi juga tidak ada nilai yang sama. Kadang-kadang, ini mungkin merupakan perilaku yang disengaja (misalnya catatan pelanggan), tetapi biasanya tidak.
Jadi, cukup buat perubahan hasil GetHashCode, ketika data objek berubah, dan jika penggunaan objek di dalam hash yang menggunakan daftar atau objek dimaksudkan (atau hanya mungkin) maka buat objek tersebut tidak dapat diubah atau buat bendera hanya-baca untuk digunakan untuk seumur hidup daftar hash yang berisi objek.
(Ngomong-ngomong: Semua ini bukan C # oder .NET spesifik - ini adalah sifat dari semua implementasi hashtable, atau lebih umum dari daftar yang diindeks, bahwa mengidentifikasi data objek tidak boleh berubah, sementara objek ada dalam daftar . Perilaku tak terduga dan tak terduga akan terjadi, jika aturan ini dilanggar. Di suatu tempat, mungkin ada implementasi daftar, yang memantau semua elemen di dalam daftar dan melakukan pengindeksan ulang daftar secara otomatis - tetapi kinerjanya pasti paling mengerikan.)