2016-01-06 1 views
1

J'essayais d'utiliser la valeur GetHashCode() pour déterminer si un objet avait été modifié après qu'il ait été validé via des appels ajax dans une application ASP.NET MVC. Cependant, j'ai remarqué que cela ne fonctionnait pas car la valeur du code de hachage renvoyée lors de la validation serait différente du code de hachage généré lorsque l'objet a été créé à partir de la liaison de modèle avec les mêmes valeurs dans une autre requête après la demande de validation. J'ai été capable de résoudre ce problème en créant un hachage SHA à la place, mais je suis curieux de savoir pourquoi je voyais ce comportement.GetHashCode() Renvoi de valeurs différentes pour des valeurs d'objet identiques

Je sais que les codes de hachage générés à partir de GetHashCode() ne doivent pas être persistants et peuvent différer sur différentes plates-formes et dans le temps. Je pensais que la période était assez courte quand j'ai eu cette idée, car ces deux appels étaient faits en millisecondes et lors du débogage, j'ai confirmé que le modèle contenait exactement les mêmes valeurs, mais produisait toujours un code de hachage différent.

Je suis curieux de savoir pourquoi ce comportement est exposé. Pourquoi cela se produirait-il même s'il s'agit d'une seule exécution de l'application, même s'il s'agit d'une application Web? Est-ce que cela a à voir avec le cycle de vie d'ASP.NET?

En cas de besoin ici est la classe & mise en œuvre GetHashCode j'utilisais:

class DispositionSubmission 
{ 
    [Display(Name = "Client")] 
    [Required(AllowEmptyStrings = false, ErrorMessage = "Client is required.")] 
    public string ClientId { get; set; } 
    public string Carrier { get; set; } 
    public Dictionary<string, string> DispositionInfo { get; set; } 
    public DispositionType Type { get; set; } //int based enum 

... 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int hash = (int)15485863; 
      int bigPrime = (int)15485867; 

      hash = hash * bigPrime^ClientId.GetHashCode(); 
      hash = hash * bigPrime^(Carrier ?? "").GetHashCode(); 
      hash = hash * bigPrime^DispositionInfo.GetHashCode(); 
      hash = hash * bigPrime^Type.GetHashCode(); 

      return hash; 
     } 
    } 
} 

Répondre

4

DispositionInfo n'a pas un type qui remplace GetHashCode(). Deux dictionnaires identiques contenant les mêmes objets auront des codes de hachage différents.

Vous devrez ajuster votre GetHashCode() pour ne pas inclure le dictionnaire ou le rendre plus complexe pour obtenir le code de hachage de chaque clé et valeur dans le dictionnaire et les additionner.

+0

Ah! Ça a du sens! * Smacks tête contre le bureau * – JNYRanger

+0

Je pencherais plus vers l'exclusion du dictionnaire, GetHashCode est censé être une fonction de retour rapide et en passant par un dictionnaire entier si grand peut être assez lent. –

+0

Il aura rarement plus de 20 paires clé-valeur, mais je dois l'inclure parce que je l'utilisais pour m'assurer que rien de changé (y compris les paires clé-valeur dans le dictionnaire) n'était utilisé. Sérialiser et générer un hachage SHA-1 a fait l'affaire. Pas la méthode la plus rapide, mais assez rapide pour ce qu'elle est utilisée. – JNYRanger

1

GetHashCode retournera le même résultat pour le même objet. Si l'objet a été réaffecté, peu importe si vous avez des valeurs identiques dans tous les champs, vous obtiendrez un résultat différent. C'est parce que ce que vous utilisez vraiment est Object.GetHashCode(), qui ne sait rien de ses autres champs de toute façon.

Ce comportement est important car si vous utilisez le hachage comme un moyen de faire référence à l'objet, la modification de l'une de ses valeurs rendrait impossible la référence à nouveau.

Si vous voulez avoir un comportement où les objets avec des champs identiques ont le même code de hachage, vous devrez l'implémenter vous-même.

Modifier: Pour clarifier: DispositionInfo, le dictionnaire, présente spécifiquement ce comportement. Les autres champs ne le sont pas, car ils sont conçus pour être immuables (string, int, etc.). Envisagez d'obtenir un hachage différent, ou en remplaçant GetHashCode par une classe personnalisée qui hérite de Dictionary<string, string>.

+0

Je me suis référé à la correction incorrecte Il fait référence à la réponse avant l'édition – SaxxonPike

+0

@SaxxonPike a vu que vous l'avez corrigé et enlevé mon commentaire/downvote – JNYRanger