Uzun zaman oldu, ancak yine de neden bu soruya doğru cevaplar vermenin gerekli olduğunu düşünüyorum. Şimdiye kadarki en iyi cevap, MSDN'yi kapsamlı bir şekilde alıntılayan cevaptır - kendi kurallarınızı yapmaya çalışmayın, MS adamları ne yaptıklarını biliyordu.
Ama önce ilk şeyler: Soruda belirtildiği gibi Kılavuz yanlıştır.
Şimdi nedenler - ikisi var
Birincisi : Eğer hashcode bir şekilde hesaplanırsa, nesnenin kendisi değişse bile, nesnenin ömrü boyunca değişmezse eşittir-kontratını kıracaktır.
Unutmayın: "İki nesne eşit olarak karşılaştırılırsa, her nesne için GetHashCode yöntemi aynı değeri döndürmelidir. Ancak, iki nesne eşit olarak karşılaştırılmazsa, iki nesne için GetHashCode yöntemlerinin farklı değerler döndürmesi gerekmez."
İkinci cümle genellikle "Tek kural, nesne oluşturma zamanında eşit nesnelerin karma kodunun eşit olması" şeklinde yanlış yorumlanır. Nedenini gerçekten bilmiyorum, ama bu burada da çoğu cevabın özü ile ilgili.
Eşit yöntemde adın kullanıldığı bir ad içeren iki nesne düşünün: Aynı ad -> aynı şey. Örnek A Oluşturun: Adı = Joe Örnek B Oluşturun: Adı = Peter
Hashcode A ve Hashcode B büyük olasılıkla aynı olmayacaktır. Şimdi B örneğinin adı Joe olarak değiştirildiğinde ne olur?
Sorudaki yönergelere göre, B'nin karma kodu değişmez. Bunun sonucu şöyle olacaktır: A.Equals (B) ==> true Ama aynı zamanda: A.GetHashCode () == B.GetHashCode () ==> false.
Ancak tam olarak bu davranış eşittir & hashcode-contract tarafından yasaklanmıştır.
İkinci neden : - Tabii ki - doğru olsa da, karma koddaki değişiklikler karma listeleri ve karma kodu kullanan diğer nesneleri bozabilir, bunun tersi de doğrudur. En kötü durumda karma kodun değiştirilmemesi, birçok farklı nesnenin hepsinin aynı karma koduna sahip olacağı ve aynı karma bölmesinde bulunacağı karma listeler alır - nesneler standart bir değerle başlatıldığında olur.
Şimdi nasıl oluyor? İlk bakışta bir çelişki var gibi görünüyor - her iki durumda da kod kırılacak. Ancak her iki sorun da değişen veya değişmeyen karma koddan gelmez.
Sorunların kaynağı MSDN'de iyi tanımlanmıştır:
MSDN'nin hashtable girişinden:
Anahtar nesneler, Hashtable'da anahtar olarak kullanıldığı sürece değişmez olmalıdır.
Bu şu anlama gelir:
Bir hashvalue oluşturan herhangi bir nesne, nesne değiştiğinde hashvalue değerini değiştirmelidir, ancak bir Hashtable (veya elbette başka bir Hash kullanan nesne) içinde kullanıldığında, kesinlikle herhangi bir değişikliğe izin vermemelidir. .
İlk olarak en kolay yol, elbette, sadece gerektiğinde normal, değişebilir nesnelerin kopyaları olarak oluşturulacak hashtable'larda kullanım için değişmez nesneleri tasarlamaktır. Değişmez nesnelerin içinde, değişmez olduğu için hash kodunu önbelleğe almak zor bir şekilde uygundur.
İkincisi Ya da nesneyi "şimdi hashediniz" olarak belirtin, tüm nesne verilerinin gizli olduğundan emin olun, nesne verilerini değiştirebilecek tüm işlevlerde bayrağı kontrol edin ve değişikliğe izin verilmiyorsa bir istisna verisi atayın (yani bayrak ayarlanmışsa) ). Şimdi, nesneyi herhangi bir karma alana koyduğunuzda, artık gerekli olmadığında bayrağı ayarladığınızdan ve - bayrağı da kaldırdığınızdan emin olun. Kullanım kolaylığı için, bayrağı "GetHashCode" yöntemi içinde otomatik olarak ayarlamanızı öneririm - bu şekilde unutulamaz. Ve bir "ResetHashFlag" yönteminin açık çağrısı, programcının nesne verilerini şu anda değiştirmesine izin verilip verilmeyeceğini düşünmek zorunda kalacaktır.
Tamam, ne söylenmeli: Eşit veriler ve hashcode-contract'ı ihlal etmeden, değiştirilebilen verileri olan nesnelerin, yine de hash kodunun değişmediği durumlar vardır.
Ancak bu, eşittir yönteminin değişebilir verilere dayanmamasını gerektirir. Yani, bir nesne yazıp bir değeri yalnızca bir kez hesaplayan ve daha sonra yapılan çağrılarda döndürmek için nesne içinde saklayan bir GetHashCode yöntemi oluşturursam, o zaman, tekrar kullanmalıyım: A.Equals (B) hiçbir zaman yanlıştan doğruya değişmeyecek şekilde karşılaştırılır. Aksi takdirde sözleşme bozulur. Bunun sonucu genellikle Eşittir yönteminin herhangi bir anlam ifade etmemesi olacaktır - orijinal referans eşit değildir, ancak her ikisi de eşit değildir. Bazen, bu amaçlanan davranış (yani müşteri kayıtları) olabilir, ancak genellikle değildir.
Bu nedenle, nesne verileri değiştiğinde GetHashCode sonucunun değişmesini sağlayın ve nesnelerin listelerin veya nesnelerin kullanılmasıyla karma içinde kullanılması amaçlanıyorsa (veya sadece mümkünse), nesneyi değiştirilemez hale getirin veya kullanmak için salt okunur bir bayrak oluşturun nesneyi içeren karma listenin ömrü.
(Bu arada: Tüm bunlar C # veya .NET'e özgü değildir - nesne listeleyken, nesnelerin verilerini tanımlamanın asla değiştirilmemesi gereken tüm karma uygulamaların veya daha genel olarak herhangi bir dizinlenmiş listenin doğasındadır. Bu kural bozulursa, beklenmedik ve öngörülemeyen davranışlar ortaya çıkar. Bir yerde, liste içindeki tüm öğeleri izleyen ve listeyi otomatik olarak yeniden dizine ekleyen liste uygulamaları olabilir - ancak bunların performansı en iyi ihtimalle kesinlikle korkunç olacaktır.)