Koks yra geriausias viršutinio „System.Object.GetHashCode“ algoritmas?

„.NET System.Object.GetHashCode metodas daugelyje vietų naudojamas visose .NET bazinės klasės bibliotekose. Ypač greitai ieškant kolekcijos elementų arba nustatant lygybę. Ar yra standartinė / geriausia praktika, skirta „ GetHashCode nepaisyti savo naudotojų klasėms, kad nesumažintų našumo?

1289
04 нояб. bitbonk yra nustatytas 04 lapkričio 2008-11-04 23:53 '08 at 11:53 2008-11-04 23:53
@ 18 atsakymų

Paprastai darau kažką panašaus į Josh Blocho „Pasakų Java“ įgyvendinimą . Tai greita ir sukuria gana gerą maišą, kuris greičiausiai nesukels susidūrimų. Pasirinkite du skirtingus pirminius numerius, pavyzdžiui, 17 ir 23, ir vykdykite:

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

Kaip pažymėta komentaruose, jums gali būti geriau pasirinkti didelį pirminį skaičių dauginimui. Akivaizdu, kad 486187739 yra geras ... ir nors dauguma pavyzdžių, kuriuos mačiau su nedideliais skaičiais, paprastai naudoja paprastus numerius, bent jau yra panašių algoritmų, kurie dažnai naudoja paprastus numerius. Pavyzdžiui, pavyzdyje su ne visai FNV, vėliau naudoju numerius, kurie atrodo gerai, bet pradinė vertė nėra paprasta. (Tačiau dauginimo konstanta yra paprasta. Nežinau, kaip tai svarbu.)

Tai geriau nei įprastinė praktika naudoti XOR maišos kodus dėl dviejų pagrindinių priežasčių. Tarkime, kad turime tipą su dviem int laukais:

 XorHash(x, x) == XorHash(y, y) == 0 for all x, y XorHash(x, y) == XorHash(y, x) for all x, y 

Beje, ankstesnį algoritmą šiuo metu naudoja C # kompiliatorius anoniminiams tipams.

Šiame puslapyje pateikiama nemažai galimybių. Manau, kad daugeliu atvejų pirmiau minėtas „pakankamai geras“ ir yra neįtikėtinai lengva prisiminti ir tinkamai suprasti. Alternatyva FNV taip pat yra paprasta, tačiau naudojasi skirtingomis konstantomis ir XOR vietoj ADD kaip prisijungimo operacijos. Jis atrodo panašus į žemiau esantį variantą, tačiau įprasta FNV algoritmas veikia su atskirais baitais, taigi tam reikės modifikacijos, kad būtų atliktas vienas iteravimas baitui, o ne 32 bitų maišos vertė. FNV taip pat yra skirtas kintamiems duomenų ilgiams, tuo tarpu mes čia visada naudojame tą patį lauko verčių skaičių. Šio atsakymo komentarai rodo, kad kodas iš tikrųjų neveikia tokiu pačiu būdu (išbandytu pavyzdžiu) kaip aukščiau aprašytas papildymo metodas.

 // Note: Not quite FNV! public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hash = (int) 2166136261; // Suitable nullity checks etc, of course :) hash = (hash * 16777619) ^ field1.GetHashCode(); hash = (hash * 16777619) ^ field2.GetHashCode(); hash = (hash * 16777619) ^ field3.GetHashCode(); return hash; } } 

Atkreipkite dėmesį, kad turėtumėte prisiminti, kad, idealiai, turėtumėte užkirsti kelią būsenai, kuri yra jautri lygybei (todėl jautriai reaguoja į maišos kodą), pakeitimą po to, kai jis pridedamas prie rinkinio, kuris priklauso nuo maišos kodo.

Pagal dokumentaciją :

Galite nepaisyti „GetHashCode“, kad būtų galima keisti nuorodų tipus. Apskritai, keičiamiems atskaitos tipams turite atsisakyti „GetHashCode“ tik tuo atveju, jei:

  • Galite apskaičiuoti maišos kodą iš laukų, kurių negalima keisti; arba
  • Galite garantuoti, kad keičiamo objekto maišos kodas nepasikeis tol, kol objektas yra kolekcijoje, kuri remiasi savo maišos kodu.
1427
04 нояб. Atsakymą pateikė Jon Skeet 2008-11-04 23:56 '08 ne 23:56 2008-11-04 23:56

Anoniminis tipas

„Microsoft“ jau teikia gerą „HashCode“ generatorių: tiesiog nukopijuokite nuosavybės / lauko vertes į anonimišką tipą ir jo turinį:

 new { PropA, PropB, PropC, PropD }.GetHashCode(); 

Tai veiks bet kokiam skaičiui savybių. Jis nenaudoja bokso. Jis tiesiog naudoja algoritmą, jau įgyvendintą anonimiškuose tipuose.

„ValueTuple“ - atnaujinimas „C # 7“

Kaip komentaruose paminėtas @cactuaroid, galite naudoti reikšmių paketą. Tai taupo keletą klavišų paspaudimų ir, dar svarbiau, veikia tik ant kamino (be šiukšlių):

 (PropA, PropB, PropC, PropD).GetHashCode(); 

(Pastaba: atrodo, kad pradinis anoniminių tipų metodas sukuria objektą krūvoje, t. Y. Šiukšliadėžėje, nes anonimiški tipai yra įgyvendinami kaip klasės, nors kompiliatorius gali jį optimizuoti. Būtų įdomu patikrinti šiuos parametrus, tačiau būtų naudinga patikrinti šiuos parametrus, tačiau parinktis turėtų būti didesnė .)

327
08 янв. Rick Love Jan 08 atsakymas 2011-01-08 00:38 '11 prie 0:38 2011-01-08 00:38

Čia yra mano pagalbininko maišos kodas.
Privalumas yra tai, kad jis naudoja bendrus argumentus ir todėl neskambina >

 public static class HashHelper { public static int GetHashCode<T1, T2>(T1 arg1, T2 arg2) { unchecked { return 31 * arg1.GetHashCode() + arg2.GetHashCode(); } } public static int GetHashCode<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3) { unchecked { int hash = arg1.GetHashCode(); hash = 31 * hash + arg2.GetHashCode(); return 31 * hash + arg3.GetHashCode(); } } public static int GetHashCode<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4) { unchecked { int hash = arg1.GetHashCode(); hash = 31 * hash + arg2.GetHashCode(); hash = 31 * hash + arg3.GetHashCode(); return 31 * hash + arg4.GetHashCode(); } } public static int GetHashCode<T>(T[] list) { unchecked { int hash = 0; foreach (var item in list) { hash = 31 * hash + item.GetHashCode(); } return hash; } } public static int GetHashCode<T>(IEnumerable<T> list) { unchecked { int hash = 0; foreach (var item in list) { hash = 31 * hash + item.GetHashCode(); } return hash; } } /// <summary> /// Gets a hashcode for a collection for that the order of items /// does not matter. /// So {1, 2, 3} and {3, 2, 1} will get same hash code. /// </summary> public static int GetHashCodeForOrderNoMatterCollection<T>( IEnumerable<T> list) { unchecked { int hash = 0; int count = 0; foreach (var item in list) { hash += item.GetHashCode(); count++; } return 31 * hash + count.GetHashCode(); } } /// <summary> /// Alternative way to get a hashcode is to use a fluent /// interface like this:<br /> /// return 0.CombineHashCode(field1).CombineHashCode(field2). /// CombineHashCode(field3); /// </summary> public static int CombineHashCode<T>(this int hashCode, T arg) { unchecked { return 31 * hashCode + arg.GetHashCode(); } } 

Jis taip pat turi išplėtimo būdą, leidžiantį suteikti nemokamą sąsają, todėl galite naudoti ją taip:

 public override int GetHashCode() { return HashHelper.GetHashCode(Manufacturer, PartN, Quantity); } 

ar panašiai:

 public override int GetHashCode() { return 0.CombineHashCode(Manufacturer) .CombineHashCode(PartN) .CombineHashCode(Quantity); } 
97
04 апр. atsakymas pateikiamas nakties koderiu 04 balandžio. 2010-04-04 21:26 '10, 21:26, 2010-04-04 21:26

Aš turiu Hashing klasę Helper bibliotekoje, kurią naudoju šiam tikslui.

 /// <summary> /// This is a simple hashing function from Robert Sedgwicks Hashing in C book. /// Also, some simple optimizations to the algorithm in order to speed up /// its hashing process have been added. from: www.partow.net /// </summary> /// <param name="input">array of objects, parameters combination that you need /// to get a unique hash code for them</param> /// <returns>Hash code</returns> public static int RSHash(params object[] input) { const int b = 378551; int a = 63689; int hash = 0; // If it overflows then just wrap around unchecked { for (int i = 0; i < input.Length; i++) { if (input[i] != null) { hash = hash * a + input[i].GetHashCode(); a = a * b; } } } return hash; } 

Tada galite jį naudoti kaip:

 public override int GetHashCode() { return Hashing.RSHash(_field1, _field2, _field3); } 

Aš nepripažinau jo veiklos, todėl atsiliepimai yra sveikintini.

59
23 февр. atsakymą pateikė Wahid Shalaly vasario 23 d. 2009-02-23 14:46 '09, 14:46, 2009-02-23 14:46

Čia yra mano pagalbininko klasė, naudojant John Skit .

 public static class HashCode { public const int Start = 17; public static int Hash<T>(this int hash, T obj) { var h = EqualityComparer<T>.Default.GetHashCode(obj); return unchecked((hash * 31) + h); } } 

Taikymas:

 public override int GetHashCode() { return HashCode.Start .Hash(_field1) .Hash(_field2) .Hash(_field3); } 

Jei norite išvengti System.Int32 pratęsimo metodo rašymo:

 public struct HashCode { private readonly int _value; public HashCode(int value) => _value = value; public static HashCode Start { get; } = new HashCode(17); public static implicit operator int(HashCode hash) => hash._value; public HashCode Hash<T>(T obj) { var h = EqualityComparer<T>.Default.GetHashCode(obj); return unchecked(new HashCode((_value * 31) + h)); } public override int GetHashCode() => _value; } 

Jis vis dar yra paplitęs, vis tiek vengia krūvos pasiskirstymo ir naudoja jį taip pat:

 public override int GetHashCode() { // This time 'HashCode.Start' is not an 'Int32', it a 'HashCode' instance. // And the result is implicitly converted to 'Int32'. return HashCode.Start .Hash(_field1) .Hash(_field2) .Hash(_field3); } 

Atnaujinkite po Martin komentaro:

obj != null sukėlė bokso, todėl perėjo į numatytąjį palyginimą.

  • Žr. „ Atsakymas į palyginimą“ pagal numatytuosius nustatymus.
  • Jei norite aptarti nulinės vertės maišos kodus, žr. Šį klausimą .

Pakeisti (2018 m. Gegužės mėn.):

EqualityComparer<T>.Default getter dabar yra vidinis JIT - prašymas dėl„ EqualityComparer<T>.Default yra paminėtas Stephen Tub šiame dienoraštyje .

51
04 сент. Şafak Gür atsakymas 04 rugsėjo. 2013-09-04 15:32 '13, 15:32 2013-09-04 15:32

Daugeliu atvejų, kai „Equals“ () lygina kelis laukus, tai tikrai nesvarbu, ar viename lauke ar daugelyje yra „GetHash“ (). Jums tereikia įsitikinti, kad maišos apskaičiavimas yra tikrai pigus (neskiriama, prašome) ir greitai ( be didelių skaičiavimų ir, be abejo, nėra ryšio su duomenų baze) ir užtikrinamas geras paskirstymas.

Sunkus kėlimas turėtų būti „Equals“ () metodo dalis; maišos turėtų būti labai pigios operacijos, leidžiančios „Equals“ () skambinti kuo mažiau elementų.

Ir paskutinis patarimas: Negalima pasikliauti GetHashCode (), kuris yra stabilus, kai naudojate kelias programas . Daugelis .Net tipų negarantuoja, kad jų pakartotiniai kodai išliks nepakitę iš naujo, todėl turite naudoti „GetHashCode“ () reikšmę atminties duomenų struktūroms.

27
23 февр. Bert Huijben atsakymas, pateiktas vasario 23 d 2009-02-23 14:55 '09 at 14:55 2009-02-23 14:55

Iki šiol mano atsakymas buvo labai artimas John Skit čia. Tačiau neseniai pradėjau projektą, kuriame buvo naudojamos dvi maišos lentelės su galios charakteristikomis, ty maišos lentelėmis, kuriose vidinės lentelės dydis yra 8, 16, 32 ir tt Yra puiki priežastis, dėl kurios pageidaujate paprastų dydžių, bet yra du privalumai.

Ir tai gana daug. Todėl po kelių eksperimentų ir tyrimų pradėjau pakartoti savo maišus su šiais būdais:

 public static int ReHash(int source) { unchecked { ulong c = 0xDEADBEEFDEADBEEF + (ulong)source; ulong d = 0xE2ADBEEFDEADBEEF ^ c; ulong a = d += c = c << 15 | c >> -15; ulong b = a += d = d << 52 | d >> -52; c ^= b += a = a << 26 | a >> -26; d ^= c += b = b << 51 | b >> -51; a ^= d += c = c << 28 | c >> -28; b ^= a += d = d << 9 | d >> -9; c ^= b += a = a << 47 | a >> -47; d ^= c += b << 54 | b >> -54; a ^= d += c << 32 | c >> 32; a += d << 25 | d >> -25; return (int)(a >> 1); } } 

Ir tada mano galios stalas su maišeliu nebėra čiulptas.

Tai man kelia nerimą, nes aukščiau paminėtas neturėtų veikti. Tiksliau, ji neturėtų veikti, jei originalus GetHashCode() buvo labai blogas.

Mišinio kodo pakartotinis maišymas negali pagerinti didelio maišos kodo, nes vienintelis galimas efektas yra tai, kad įvedame dar kelis susidūrimus.

Maišymo kodo pakartotinis maišymas negali pagerinti siaubingo maišos kodo, nes vienintelis galimas efektas yra tai, kad mes, pvz., Pakeisime didelį susidūrimų skaičių pagal reikšmę 53 iki daugelio reikšmių 18,3487,291.

Maišymo kodo pakartotinis maišymas gali tik pagerinti maišos kodą, kuris yra bent jau pakankamai geras, kad būtų išvengta absoliutų susidūrimų per visą diapazoną (2 32 galimų verčių), tačiau blogai išvengti susidūrimų su moduliniu naudojimu faktiškam maišymo lentelėje. Nors supaprastinta modulių „dviejų jėgų“ lentelė tapo aiškesnė, ji taip pat turėjo neigiamos įtakos bendresnėms bazinėms lentelėms, o ne skaičiui, kurios paprasčiausiai nebuvo tokios akivaizdžios (papildomas darbas dėl perskirstymo būtų didesnis už naudą, bet naudą). jis bus lygus ten).

Redaguoti: taip pat naudoju atvirą adresą, kuris taip pat padidintų susidūrimo jautrumą, galbūt daugiau nei tai, kad tai buvo dviejų galia.

Ir gerai, ji bothered kiek string.GetHashCode() galėjo būti string.GetHashCode() įgyvendinimas .NET (arba mokėsi čia ) (pagal bandymus, atliktus 20-30 kartų greičiau dėl mažiau susidūrimų) ir daugiau gali būti patobulintas daugelis mano maišos kodų (daug daugiau).

Visi „GetHashCode“ () įvykiai, kuriuos aš užkodavau praeityje ir iš tikrųjų naudojami kaip atsakymai šioje svetainėje, buvo daug blogesni už mane . Daugeliu atvejų ji buvo „pakankamai gera“ daugumai programų, bet norėjau kažką geriau.

Todėl šį projektą įdėjau į vieną pusę (tai buvo naminių gyvūnų projektas) ir pradėjau ieškoti, kaip greitai sukurti gerą, gerai paskirstytą maišos kodą .NET.

Galų gale aš nusprendžiau prijungti „SpookyHash“ į .NET. Iš tiesų, minėtas kodas yra versija, kurioje spartyHash galima greitai sukurti 32 bitų išvestį iš 32 bitų.

Dabar „SpookyHash“ labai gerai neprisimena kodo. Mano uostas yra dar mažesnis, nes aš rankiniu būdu nustatiau daug geresnio greičio *. Bet koks yra kodo pakartotinis naudojimas?

Tada aš įdėjau šį projektą į vieną pusę, nes, kaip ir pradiniame projekte, iškilo klausimas, kaip sukurti geriausią maišos kodą, kad projektas paklaustų, kaip sukurti geriausią .NET memcpy.

Tada aš grįžau ir išleidau daug perkrovos, kad būtų lengvai įkelti beveik visi pilno dydžio tipai (išskyrus decimal ) į maišos kodą.

Tai greita, dėl kurios Bob Jenkins nusipelno didžiosios dalies kredito, nes jo pirminis kodas, kurį aš perkėliau, yra greitesnis, ypač 64 bitų mašinose, algoritmas yra optimizuotas ‡.

Visą kodą galima pamatyti adresu https://bitbucket.org/JonHanna/spookilysharp/src, tačiau atkreipkite dėmesį, kad aukščiau nurodytas kodas yra supaprastinta versija.

Tačiau, kadangi jis jau yra parašytas, galite jį lengvai naudoti:

 public override int GetHashCode() { var hash = new SpookyHash(); hash.Update(field1); hash.Update(field2); hash.Update(field3); return hash.Final().GetHashCode(); } 

Ji taip pat priima sėklų vertes, taigi, jei jums reikia spręsti nepatikimą įvestį ir norite apsaugoti nuo „Hash DoS“ atakų, galite nustatyti sėklą pagal veiksnumo laiką arba panašius duomenis ir padaryti rezultatus nenuspėjamus užpuolikus:

 private static long hashSeed0 = Environment.TickCount; private static long hashSeed1 = DateTime.Now.Ticks; public override int GetHashCode() { //produce different hashes ever time this application is restarted //but remain consistent in each run, so attackers have a harder time //DoSing the hash tables. var hash = new SpookyHash(hashSeed0, hashSeed1); hash.Update(field1); hash.Update(field2); hash.Update(field3); return hash.Final().GetHashCode(); } 

* Didelis siurprizas yra tai, kad rankinis grąžinimo metodo įdėjimas (x << n) | (x >> -n) (x << n) | (x >> -n) (x << n) | (x >> -n) (x << n) | (x >> -n) pagerino situaciją. Būčiau tikras, kad drebėjimas investuotų jį už mane, bet profiliavimas parodė kitaip.

decimal nėra vietinis .NET, nors jis yra iš C #. Problema ta, kad jos paties GetHashCode() tikslumą laiko reikšmingu, o savo „ Equals() nėra. Abu yra galiojantys, bet nevienodi. Įgyvendindami savo versiją turite pasirinkti vieną ar kitą, bet aš negaliu žinoti, ko norite.

Comparison Palyginimui. SpookyHash yra 64 bitų žymiai greičiau nei string.GetHashCode() yra 32 bitai, tai yra šiek tiek greičiau nei string.GetHashCode() yra 64 bitai, o tai yra daug greičiau nei SpookyHash 32 bitai, nors jis vis dar yra greitas pakankamai, kad būtų protingas pasirinkimas.

20
14 янв. Atsakymą Jon Hanna pateikė sausio 14 d. 2014-01-14 17:15 '14, 17:15, 2014-01-14 17:15

Tai geras pasirinkimas:

 /// <summary> /// Helper class for generating hash codes suitable /// for use in hashing algorithms and data structures like a hash table. /// </summary> public static class HashCodeHelper { private static int GetHashCodeInternal(int key1, int key2) { unchecked { var num = 0x7e53a269; num = (-1521134295 * num) + key1; num += (num << 10); num ^= (num >> 6); num = ((-1521134295 * num) + key2); num += (num << 10); num ^= (num >> 6); return num; } } /// <summary> /// Returns a hash code for the specified objects /// </summary> /// <param name="arr">An array of objects used for generating the /// hash code.</param> /// <returns> /// A hash code, suitable for use in hashing algorithms and data /// structures like a hash table. /// </returns> public static int GetHashCode(params object[] arr) { int hash = 0; foreach (var item in arr) hash = GetHashCodeInternal(hash, item.GetHashCode()); return hash; } /// <summary> /// Returns a hash code for the specified objects /// </summary> /// <param name="obj1">The first object.</param> /// <param name="obj2">The second object.</param> /// <param name="obj3">The third object.</param> /// <param name="obj4">The fourth object.</param> /// <returns> /// A hash code, suitable for use in hashing algorithms and /// data structures like a hash table. /// </returns> public static int GetHashCode<T1, T2, T3, T4>(T1 obj1, T2 obj2, T3 obj3, T4 obj4) { return GetHashCode(obj1, GetHashCode(obj2, obj3, obj4)); } /// <summary> /// Returns a hash code for the specified objects /// </summary> /// <param name="obj1">The first object.</param> /// <param name="obj2">The second object.</param> /// <param name="obj3">The third object.</param> /// <returns> /// A hash code, suitable for use in hashing algorithms and data /// structures like a hash table. /// </returns> public static int GetHashCode<T1, T2, T3>(T1 obj1, T2 obj2, T3 obj3) { return GetHashCode(obj1, GetHashCode(obj2, obj3)); } /// <summary> /// Returns a hash code for the specified objects /// </summary> /// <param name="obj1">The first object.</param> /// <param name="obj2">The second object.</param> /// <returns> /// A hash code, suitable for use in hashing algorithms and data /// structures like a hash table. /// </returns> public static int GetHashCode<T1, T2>(T1 obj1, T2 obj2) { return GetHashCodeInternal(obj1.GetHashCode(), obj2.GetHashCode()); } } 

Ir kaip tai naudoti:

 private struct Key { private Type _type; private string _field; public Type Type { get { return _type; } } public string Field { get { return _field; } } public Key(Type type, string field) { _type = type; _field = field; } public override int GetHashCode() { return HashCodeHelper.GetHashCode(_field, _type); } public override bool Equals(object obj) { if (!(obj is Key)) return false; var tf = (Key)obj; return tf._field.Equals(_field)  tf._type.Equals(_type); } } 
13
07 окт. atsakymas pateikiamas Magnus spalis 07. 2010-10-07 13:51 '10, 13:51, 2010-10-07 13:51

Čia yra dar vienas dabartinio „Jon Skeet“ paskelbto algoritmo įgyvendinimas, tačiau jame nėra bokso paskirstymo ar operacijų:

 public static class Hash { public const int Base = 17; public static int HashObject(this int hash, object obj) { unchecked { return hash * 23 + (obj == null ? 0 : obj.GetHashCode()); } } public static int HashValue<T>(this int hash, T value) where T : struct { unchecked { return hash * 23 + value.GetHashCode(); } } } 

Naudoti:

 public class MyType<T> { public string Name { get; set; } public string Description { get; set; } public int Value { get; set; } public IEnumerable<T> Children { get; set; } public override int GetHashCode() { return Hash.Base .HashObject(this.Name) .HashObject(this.Description) .HashValue(this.Value) .HashObject(this.Children); } } 

Kompiliatorius užtikrina, kad „ HashValue nebūtų vadinama klasė dėl bendro tipo apribojimo. Tačiau „ HashObject nėra kompiliatoriaus palaikymo, nes pridėjus bendrą argumentą taip pat pridedama bokso operacija.

9
21 янв. Scott Wegner atsakymas dėl sausio 21 d 2014-01-21 02:41 '14 at 2:41 2014-01-21 02:41

Čia yra mano supaprastintas požiūris. Tam naudoju klasikinį statytojo šabloną. Tai yra tipai (be bokso / išpakavimo), taip pat suderinami su .NET 2.0 (be plėtinių metodų ir pan.).

Jis naudojamas taip:

 public override int GetHashCode() { HashBuilder b = new HashBuilder(); b.AddItems(this.member1, this.member2, this.member3); return b.Result; } 

Ir čia yra akutinio statytojo klasė:

 internal class HashBuilder { private const int Prime1 = 17; private const int Prime2 = 23; private int result = Prime1; public HashBuilder() { } public HashBuilder(int startHash) { this.result = startHash; } public int Result { get { return this.result; } } public void AddItem<T>(T item) { unchecked { this.result = this.result * Prime2 + item.GetHashCode(); } } public void AddItems<T1, T2>(T1 item1, T2 item2) { this.AddItem(item1); this.AddItem(item2); } public void AddItems<T1, T2, T3>(T1 item1, T2 item2, T3 item3) { this.AddItem(item1); this.AddItem(item2); this.AddItem(item3); } public void AddItems<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4) { this.AddItem(item1); this.AddItem(item2); this.AddItem(item3); this.AddItem(item4); } public void AddItems<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) { this.AddItem(item1); this.AddItem(item2); this.AddItem(item3); this.AddItem(item4); this.AddItem(item5); } public void AddItems<T>(params T[] items) { foreach (T item in items) { this.AddItem(item); } } } 
8
22 марта '11 в 15:15 2011-03-22 15:15 atsakymas pateikiamas bitbonk kovo 22 d. 11 val. 15:15 2011-03-22 15:15

Pradedant nuo https://github.com/dotnet/coreclr/pull/14863 , yra naujas būdas generuoti maišos kodus, kuris yra labai paprastas! Tiesiog parašykite

 public override int GetHashCode() => HashCode.Combine(field1, field2, field3); 

Tai sukurs kokybišką maišymo kodą, nerimaudamas dėl įgyvendinimo detalių.

6
23 нояб. James Ko atsakymas pateiktas lapkričio 23 d 2017-11-23 18:06 '17 at 18:06 2017-11-23 18:06

„ReSharper“ vartotojai gali generuoti „GetHashCode“, „Equals“ ir kt. Naudodami „ ReSharper → Edit → Generate Code → Equality Members .

 // ReSharper GetHashCode looks like this public override int GetHashCode() { unchecked { int hashCode = Id; hashCode = (hashCode * 397) ^ IntMember; hashCode = (hashCode * 397) ^ OtherIntMember; hashCode = (hashCode * 397) ^ (RefMember != null ? RefMember.GetHashCode() : 0); // ... return hashCode; } } 
4
01 сент. Charles Burns atsakymas rugsėjo 01 d 2016-09-01 22:19 '16 at 22:19 pm 2016-09-01 22:19

Labai patinka naktinio kodo sprendimas, išskyrus tai, kad, jei norite, lengviau pasiimti svarbiausius numerius.

PS: Tai vienas iš tų laikų, kai turite mažai burnos skalavimo, žinodami, kad jis gali būti reorganizuotas į vieną metodą su 9 standartais, tačiau jis bus lėčiau, todėl jūs tiesiog uždarysite akis ir pabandykite užmiršti.

 /// <summary> /// Try not to look at the source code. It works. Just rely on it. /// </summary> public static class HashHelper { private const int PrimeOne = 17; private const int PrimeTwo = 23; public static int GetHashCode<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); hash = hash * PrimeTwo + arg5.GetHashCode(); hash = hash * PrimeTwo + arg6.GetHashCode(); hash = hash * PrimeTwo + arg7.GetHashCode(); hash = hash * PrimeTwo + arg8.GetHashCode(); hash = hash * PrimeTwo + arg9.GetHashCode(); hash = hash * PrimeTwo + arg10.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3, T4, T5, T6, T7, T8, T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); hash = hash * PrimeTwo + arg5.GetHashCode(); hash = hash * PrimeTwo + arg6.GetHashCode(); hash = hash * PrimeTwo + arg7.GetHashCode(); hash = hash * PrimeTwo + arg8.GetHashCode(); hash = hash * PrimeTwo + arg9.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3, T4, T5, T6, T7, T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); hash = hash * PrimeTwo + arg5.GetHashCode(); hash = hash * PrimeTwo + arg6.GetHashCode(); hash = hash * PrimeTwo + arg7.GetHashCode(); hash = hash * PrimeTwo + arg8.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3, T4, T5, T6, T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); hash = hash * PrimeTwo + arg5.GetHashCode(); hash = hash * PrimeTwo + arg6.GetHashCode(); hash = hash * PrimeTwo + arg7.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3, T4, T5, T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); hash = hash * PrimeTwo + arg5.GetHashCode(); hash = hash * PrimeTwo + arg6.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); hash = hash * PrimeTwo + arg5.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); hash = hash * PrimeTwo + arg4.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); hash = hash * PrimeTwo + arg3.GetHashCode(); return hash; } } public static int GetHashCode<T1, T2>(T1 arg1, T2 arg2) { unchecked { int hash = PrimeOne; hash = hash * PrimeTwo + arg1.GetHashCode(); hash = hash * PrimeTwo + arg2.GetHashCode(); return hash; } } } 
3
ответ дан Dbl 21 окт. '14 в 20:49 2014-10-21 20:49