Nepaisyti „GetHashCode“ ()

Šiame straipsnyje John Skeat paminėjo, kad jis dažniausiai naudoja tokį algoritmą, kad panaikintų GetHashCode ().

 public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hash = 17; // Suitable nullity checks etc, of course :) hash = hash * 23 + Id.GetHashCode(); return hash; } } 

Dabar aš bandžiau jį naudoti, tačiau „Resharper“ pasakoja, kad „GetHashCode“ () metodas turėtų būti naudojamas tik naudojant tik skaitymui skirtus laukus (nors ji surenkama gerai). Kas būtų gera praktika, nes dabar aš negaliu turėti savo tik skaitymui laukų?

Bandžiau sukurti šį metodą naudojant „Resharper“, čia yra rezultatas.

 public override int GetHashCode() { return base.GetHashCode(); } 

Ji neprisideda, sąžiningai ...

20
14 июля '12 в 8:27 2012-07-14 08:27 Pacane yra nustatytas liepos 14 d., 12 val., 08:27, 2012-07-14 08:27
@ 3 atsakymai

Jei visi laukai yra keičiami ir jums reikia įdiegti GetHashCode metodą, aš bijau, kad tai bus jūsų įgyvendinimas.

 public override int GetHashCode() { return 1; } 

Taip, tai neveiksminga, tačiau ji yra bent jau teisinga.

Problema ta, kad „ GetHashCode “ žodynas ir „HashSet“ rinkiniai naudoja kiekvieną elementą į kibirą. Jei hashcode apskaičiuojamas pagal kai kuriuos kintamuosius laukus, o laukai pasikeičia po to, kai objektas įdedamas į „HashSet“ arba žodyną, objektas nebebus randamas „HashSet“ ar „Dictionary“.

Atkreipkite dėmesį, kad visi objektai, grįžtantys į tą patį „HashCode 1“, iš esmės reiškia, kad visi objektai yra patalpinami toje pačioje kibiroje „HashSet“ arba „Dictionary“. Taigi „HashSet“ arba „Dictionary“ visada yra tik vienas kibiras. Bandydamas surasti objektą, jis tikrins kiekvieno objekto lygybės patikrinimą viename kibire. Tai panaši į paiešką susietame sąraše.

Kai kurie gali teigti, kad hashcode įgyvendinimas pagal kintamuosius laukus gali būti gerai, jei galime įsitikinti, kad laukai nekeičiami po to, kai objektai pridedami prie „HashCode“ arba „Dictionary“ rinkinio. Mano asmeninė nuomonė yra ta, kad ji yra klaidinga. Kažkas, kuris per dvejus metus paima jūsų kodą, gali nežinoti apie tai ir netyčia nutraukti kodą.

16
14 июля '12 в 9:18 2012-07-14 09:18 atsakymą pateikė Harvey Kwok liepos 14 d., 12 val

Atminkite, kad „GetHashCode“ turėtų eiti kartu su „Equals“ metodu. Ir jei jūs galite tiesiog naudoti atskaitos lygybę (kai jūs niekada neturite dviejų skirtingų klasių atvejų, kurie gali būti lygūs), galite saugiai naudoti „Equals“ ir „GetHashCode“, kurie yra paveldėti iš objekto. Tai veiks daug geriau nei tik return 1 iš „GetHashCode“.

5
14 июля '12 в 18:39 2012-07-14 18:39 atsakymą pateikė Dmitrijus Osinovskis, liepos 14 d., 12 val. 6:39 2012-07-14 18:39

Aš asmeniškai GetHashCode() grąžinti skirtingą skaitinę vertę kiekvienam „ GetHashCode() diegimui klasėje, kurioje nėra nekintamų laukų. Tai reiškia, kad jei turiu žodyną, kuriame yra skirtingų tipų diegimo būdų, yra galimybė, kad skirtingų tipų egzemplioriai bus patalpinti į skirtingus kibirus.

Pavyzdžiui

 public class A { // TODO Equals override public override int GetHashCode() { return 21313; } } public class B { // TODO Equals override public override int GetHashCode() { return 35507; } } 

Tada, jei turiu Dictionary<object, TValue> kuriame yra A , B ir kitų tipų pavyzdžiai, paieškos našumas būtų geresnis nei tuo atveju, jei visos „ GetHashCode gautų tą pačią skaitmeninę vertę.

Taip pat reikėtų pažymėti, kad noriu gauti geriausią paskirstymą naudoju pirminius numerius.

Pagal komentarus čia pateikiau LINQPad pavyzdį, kuris parodo skirtumą tarp skirtingų tipų return 1 naudojimo ir kiekvieno tipo grąžinimo.

-1
29 окт. atsakymas pateikiamas Lukazoid 29 okt. 2013-10-29 12:54 '13, 12:54, 2013-10-29 12:54

Žr. Kitus klausimus apie „ arba užduokite klausimą