IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

[CLR .Net 2]Relation entre GetHashCode() et Equals()


Sujet :

Framework .NET

  1. #1
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut [CLR .Net 2]Relation entre GetHashCode() et Equals()
    Voici un court programme.
    Que retourne t-il ?
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // On récupère un MemberInfo, n'importe laquelle
    MemberInfo mi1 = typeof(XmlDocument).GetMethod("ToString");
    // On récupère son module et son MetadataToken
    Module module = mi1.Module;
    int token = mi1.MetadataToken;
    // On retrouve le MemberInfo dans le module, grâce au token
    MemberInfo mi2 = module.ResolveMember(token);
     
    // et là... j'hallucine
    Console.WriteLine((mi1 == mi2) + " = (mi1 == mi2)");
    Console.WriteLine((mi1.Equals(mi2)) + " = (mi1.Equals(mi2))");
    Console.WriteLine(MemberInfo.ReferenceEquals(mi1, mi2) + " = (MemberInfo.ReferenceEquals(mi1, mi2)");
    Console.WriteLine((mi1.GetHashCode() == mi2.GetHashCode()) + " = (mi1.GetHashCode() == mi2.GetHashCode()");
    Console.ReadLine();
    Réponse :
    Faux
    Faux
    Faux
    Vrai

    Quelqu'un peut m'expliquer comment c'est possible ?

    Mose, très énervé contre MS qui sait pas gérer la compatiblité ascendante

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Points : 1 046
    Points
    1 046
    Par défaut
    Salut,

    Je ne comprends pas ton problème, tu as deux références différentes d'objet de type MemberInfo qui représentent la même méthode, je ne suis pas choqué du résultat (apparemment ni l'opérateur d'égalité ni la méthode Equals n'ont été surchargé par MemberInfo et ils font donc un test dégalité des références).

    L'important dans la relation entre l'égalité et le hashCode c'est : si A = B alors hashCode(A) = hashCode(B) , pas la réciproque.

    Mose, très énervé contre MS qui sait pas gérer la compatiblité ascendante
    là encore je ne vois pas ce que tu veux dire, mais peut-être que je passe à côté du pb...

  3. #3
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Citation Envoyé par Sphax
    L'important dans la relation entre l'égalité et le hashCode c'est : si A = B alors hashCode(A) = hashCode(B) , pas la réciproque.
    Précisémment.
    La réciproque était vrai en fx1.1.
    En 2.0, je peux m'asseoir dessus et refaire tout un pan de l'archi de mon projet.

    Question 1 : si je fais une Hashtable dans laquelle je colle mi1, mon premier MemberInfo, qu'est ce qui doit être utilisé comme hashcode pour mon objet ?

    Question 2 : Comment ça se fait qu'un code sensé identifier de façon unique un objet soit le même alors que les références diffèrent ? Je l'admet pour les types valeur, mais pour les types références, ça me dérange beaucoup.

    Pour retourner sur mon exemple particulier :
    Fonctionnellement, mes deux MemberInfos sont identiques (ils pointent vers la même méthode)
    Techniquement, en fx1.1, j'obtenais la même instance en passant par le type + le nom du membre + ses paramètres (mais c'était assez lourd)
    Maintenant, en fx2.0, je l'ai dans l 'os... falloir refaire toutes mes collections pour ajouter un @~#^{# de GetHashCode() partout....

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Points : 1 046
    Points
    1 046
    Par défaut
    La réciproque était vrai en fx1.1.
    Seulement MS n'a jamais garanti ça, ni que ça le resterait. Moi j'ai toujours lu que la seule chose garantie était "si A = B alors hashCode(A) = hashCode(B)" , a partir de là libre à MS de changer l'implémentationde leur gethashCode si ça leur chante.

    Dans la même idée ils n'ont jamais dit que GetHashCode renverrait la même valeur pour un même objet d'une version du framework a l'autre et donc il ne faut pas faire dépendre son appli de ça (genre stocker en base de données des hashCode...).

    Comment ça se fait qu'un code sensé identifier de façon unique un objet soit le même alors que les références diffèrent ?
    Le HashCode ne sert pas à identifier de manière unique un objet (et encore moins des références d'objet),même s'il y a de fortes probabilités que ce soit le cas, ou as-tu vu ça ? L'important dans le HashCode c'est qu'il offre une bonne répartition des objets pour qu'une hashTable basée dessus soit efficace. Ce hashCode est d'ailleurs souvent (toujours ?) basé sur le contenu des objets et donc je ne suis pas choqué que deux instances différentes d'un même objet renvoient le même HashCode (c'est même le comportement voulu, sinon ta HashTable ne marche pas).

    Pour le reste je ne comprends pas ton problème.

  5. #5
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Nan attend.... y'a maldonne.

    Point 1 : Je ne stocke pas les HashCode. Ca n'a pas de sens, ils changent d'une exécution à l'autre du même programme.

    En revanche, j'était persuadé qu'ils servaient de clef pour faire des ajouts dans les Hashtable, et je me suis trompé. Moralité : cette fonction GetHashCode(), en plus de ne servir à rien, est là pour tromper le développeur, ce que je trouve particulièrement fourbe de la part de MS. (point 1 résolu)

    Point 2 : Effectivement, il était très naif de ma part de croire un Hashcode unique à un objet. Néanmoins, dans la pratique c'est a peu près vrai, sauf si on instancie plus de Int32.Max instances à la fois, ce qui arrive assez rarement (je t'invite à faire un programme pour le vérifier)

    Point 3 : Mon problème, je viens de le cerner plus précisémment :
    * J'ai une classe A qui implémente une méthode DoIt()
    * J'ai une classe B qui hérite de A et n'implémente rien.
    * Je récupère le MemberInfo m1 de la méthode DoIt depuis le Type A
    * Je récupère le MemberInfo m2 de la méthode DoIt depuis le Type B
    * m1 == m2 ?

    Réponse :
    en fx1.1 : oui (framework 1.1)
    en fx2.0 : non

    Moralité : mon appli qui fonctionne à fond sur la Reflection (normal c'est son job) déconne de partout parce que la même méthode peut maintenant être désignée par deux instances différentes.
    Merci MS pour la compatibilité ascendante.

    Je déleste ce post et je retourne trouve une autre solution...

  6. #6
    Membre expérimenté
    Avatar de Mehdi Feki
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 113
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 113
    Points : 1 566
    Points
    1 566
    Par défaut
    Malgres le delestage, je voudrais bien entrer avec vous dans le débatq ue je trouve assez interressant.

    Citation Envoyé par Sphax
    ? L'important dans le HashCode c'est qu'il offre une bonne répartition des objets pour qu'une hashTable basée dessus soit efficace. Ce hashCode est d'ailleurs souvent (toujours ?) basé sur le contenu des objets et donc je ne suis pas choqué que deux instances différentes d'un même objet renvoient le même HashCode.
    Rien à dire, parfaite explication . Manque juste une chose, si la Hashtable trouve deux hash identiques, elle va ensuite comparer les deux objets en appelant la méthode equals, et là ça peut répondre à ta question Mose : 2 objets peuvent avoir 2 hash identiques mais ils ne sont pas égaux, il faut juste définir la sémantique de equals.

    Et donc - et là il suffit de vérifier- dans ton 1er exemple m1 et m2 vont êtres 2 clés différentes de ta Hashtable.

    Citation Envoyé par Mose
    En revanche, j'était persuadé qu'ils servaient de clef pour faire des ajouts dans les Hashtable, et je me suis trompé. Moralité : cette fonction GetHashCode(), en plus de ne servir à rien, est là pour tromper le développeur, ce que je trouve particulièrement fourbe de la part de MS. (point 1 résolu)
    Là tu trompes Mose, et d'ailleurs sur tout ce que tu dis à propos de MS. GetHashCode ( qui n'est rien qu'une valeur de hashage ) est le fondement des Dictionnaires, sans elle ces derniers n'existraient plus. Pour cela je t'invite de te documener sur les tables de hashages et sur la maniere avec laquelle l'insertion se fait dans une T de H. Je t'aide un peu : comment à ton avis la recherche dans une T de H est à peu pres en O(1) ?
    Mehdi Feki : Modérateur .Net

  7. #7
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Je connais le principe Medhi.
    Et je pensais la même chose que toi, jusqu'à il y a 3 jour où j'ai trouvé un contre exemple... et mes convictions se sont écroulées.
    Franchement, j'aimerait bien me tromper, là ça m'oblige à refaire plein de trucs dans mon IDE...

    Je t'invite à tester :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // Je récupère une MemberInfo hérité
    MemberInfo mi1 = typeof(System.Xml.XmlDocument).GetMethod("ToString");
    // Je récupère son module et le token associé
    Module module = mi1.Module;
    int token = mi1.MetadataToken;
    // Dans le module, je récupère le même MemberInfo (grâce au token qui est sensé l'identifier de façon unique)
    MemberInfo mi2 = module.ResolveMember(token);
     
    // s(ils ont le même hash code
    if(mi1.GetHashCode() == mi2.GetHashCode())
    {
    	Console.WriteLine("Ils ont le même hash code");
    	// je créé une hashtable
    	Hashtable ht = new Hashtable();
    	// je met mi1 comme clef dedans
    	ht.Add(mi1, null);
    	// puis je cherche, en utilisant un objet clef qui a le même hashcode
    	Console.WriteLine("Alors ? Il est buggé le framework ? " + !(ht.Contains(mi2)));
    }
    Console.ReadLine();
    Questions :
    * à quoi sert GetHashCode alors ?
    * qu'est ce qui sert de clef dans les HashTable ?

    (Note : j'ai peut-être un début de réponse, mais celle-ci ne me plait pas du tout en tant que developpeur d'applications déterministes)

  8. #8
    Membre expérimenté
    Avatar de Mehdi Feki
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 113
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 113
    Points : 1 566
    Points
    1 566
    Par défaut
    Citation Envoyé par Mose
    * à quoi sert GetHashCode alors ?
    * qu'est ce qui sert de clef dans les HashTable ?
    Je crois que j'ai déja répondu à tes questions

    Citation Envoyé par mehdi_tn
    si la Hashtable trouve deux hash identiques, elle va ensuite comparer les deux objets en appelant la méthode equals
    Ensuite si tu connais le principe de la hashtable alors tu connais à quoi sert une clé de hashage (GetHashCode), une fonction de hashage aussi.

    Où j'ai loupé quelque chose ??
    Mehdi Feki : Modérateur .Net

  9. #9
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Bein teste le code que j'ai envoyé, et explique moi le résultat svp
    Je suis sur le cul, très franchement.

    J'ai deux objets A et B qui ont le même hahs code
    je met A dans une Hashtable
    en me servant du hashcode de B, la recherche ne me retourne rien...

  10. #10
    Membre expérimenté
    Avatar de Mehdi Feki
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 113
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 113
    Points : 1 566
    Points
    1 566
    Par défaut
    Citation Envoyé par Mose
    Bein teste le code que j'ai envoyé, et explique moi le résultat svp
    Pas de ça entre nous, un petit stp me suffit

    Ok, je vais être plus clair.

    la question qui se pose comment une hashtable en .Net vérifie qu'une clé existe déja. ?

    1. D'abord elle va comparer le hash de l'objet à vérifier, 2 cas se présentent :
      • Aucun hash de même valeur existe dans la HT, dans ce cas la clé n'existe pas dans la HT
      • un objet avec le même hash existe déja ; c'est ton cas alors on passe à la deuxieme étape
    2. Puisque une clé avec le même hash existe déja, on va donc comparer les 2 clés avec les méthodes equals, dans ton cas la comparaison retourne false et par suite la clé n'existe pas dans la HT.


    J'espere que c'est plus clair maintenant !!!
    Mehdi Feki : Modérateur .Net

  11. #11
    Membre expérimenté Avatar de Mose
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 143
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 143
    Points : 1 379
    Points
    1 379
    Par défaut
    Ok, merci pour ton explication. Confirmé par Reflector

    Bon... maintenant mon principal problème concerne les modifications de System.Reflection.MemberInfo entre les deux frameworks... mais j'ai ptet trouvé une bidouille.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2003] les relations entre tables access avec un code vb.net
    Par Walid(Tun) dans le forum VBA Access
    Réponses: 5
    Dernier message: 13/10/2010, 22h31
  2. Réponses: 4
    Dernier message: 22/08/2006, 11h20
  3. [C++.NET] Relation entre 2 colonnes de mon data
    Par raboin dans le forum VC++ .NET
    Réponses: 21
    Dernier message: 15/05/2006, 14h25
  4. Relations entre les Paquetages
    Par bran_noz dans le forum UML
    Réponses: 4
    Dernier message: 25/06/2004, 14h05
  5. [Relations] afficher les relations entre 2 tables
    Par dzincou dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 14/01/2004, 17h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo