46 votes

Pourquoi ne Système de.Type.GetHashCode retourner la même valeur pour toutes les instances et les types?

Le code suivant génère la sortie de 46104728:

using System;

namespace TestApplication
{
    internal static class Program
    {
        private static void Main()
        {
            Type type = typeof(string);
            Console.WriteLine(type.GetHashCode());
            Console.ReadLine();
        }
    }
}

Mais donc cela:

using System;

namespace TestApplication
{
    internal static class Program
    {
        private static void Main()
        {
            Type type = typeof(Program);
            Console.WriteLine(type.GetHashCode());
            Console.ReadLine();
        }
    }
 }

Encore sur http://ideone.com il produit des résultats différents pour chaque type. Ce problème a été reproduit sur plus d'un système maintenant. Je suis en utilisant .NET 4.0 maintenant.

47voto

user7116 Points 39829

Vous avez ce que vous croyez être un problème, cependant, si vous regardez leurs codes de hachage dans la même exécution , vous trouverez qu'ils ne sont pas identiques, mais plutôt s'appuyer sur leur ordre d'utilisation:

Console.WriteLine("{0} {1:08X}", typeof(string), typeof(string).GetHashCode());
Console.WriteLine("{0} {1:08X}", typeof(Program), typeof(Program).GetHashCode());
// System.String 02BF8098
// Program 00BB8560

Si je l'exécuter à nouveau le programme, la permutation de leur ordre:

Console.WriteLine("{0} {1:08X}", typeof(Program), typeof(Program).GetHashCode());
Console.WriteLine("{0} {1:08X}", typeof(string), typeof(string).GetHashCode());
// Program 02BF8098
// System.String 00BB8560

C'est un non-problème lors de l'exécution que les valeurs renvoyées à ne pas violer les règles de mise en œuvre de Object.GetHashCode.

Mais, comme vous l'avez remarqué ce comportement semble curieux!

J'ai fouillé dans la source et a constaté la mise en œuvre de l' Type.GetHashCode est imposée sur MemberInfo.GetHashCode, qui est de nouveau imposé sur Object.GetHashCode qui demande RuntimeHelpers.GetHashCode(this).

C'est à ce moment que la piste va froid, cependant, mon hypothèse, c'est le fonctionnement interne de cette méthode crée une nouvelle valeur, cartographiée par exemple, basé sur l'ordre des appels.

J'ai testé cette hypothèse en exécutant le code ci-dessus avec deux instances de l' Program (après l'ajout d'une propriété à les identifier):

var b = new Program() { Name = "B" };
var a = new Program() { Name = "A" };
Console.WriteLine("{0} {1:08X}", a.Name, a.GetHashCode());
Console.WriteLine("{0} {1:08X}", b.Name, b.GetHashCode());
// A 02BF8098
// B 00BB8560

Ainsi, pour les classes qui ne sont pas explicitement remplacent Object.GetHashCode, les instances seront attribués apparemment prévisible de la valeur de hachage basée sur l'ordre dans lequel ils appellent GetHashCode.


Mise à jour: j'ai regardé comment Rotor/Shared Source CLI gère cette situation, et j'ai appris que le défaut de mise en œuvre de calcule et mémorise un code de hachage de la synchronisation de bloc pour l'instance de l'objet, assurant ainsi le code de hachage est généré qu'une seule fois. La valeur par défaut de calcul pour ce code de hachage est trivial, et utilise par thread de semences (emballage est le mien):

// ./sscli20/clr/src/vm/threads.h(938)
// Every thread has its own generator for hash codes so that we
// won't get into a situation where two threads consistently give
// out the same hash codes.
// Choice of multiplier guarantees period of 2**32
// - see Knuth Vol 2 p16 (3.2.1.2 Theorem A).

Donc, si le CLR suit cette mise en œuvre, il semblerait toutes les différences observées dans le code de hachage de valeurs pour les objets sont basés sur le domaine d'application et Géré Thread qui a créé l'instance.

10voto

leppie Points 67289

Programme (.NET 4, AnyCPU):

var st = typeof(string);
var pt = typeof(Program);
Console.WriteLine(st.GetHashCode());
Console.WriteLine(pt.GetHashCode());
Console.WriteLine(typeof(string).GetHashCode());
Console.WriteLine(typeof(Program).GetHashCode());
Console.ReadLine();

Parcours 1:

33156464
15645912
33156464
15645912

Exécuter 2-6:

45653674
41149443
45653674
41149443

Exécutez 7:

46104728
12289376
46104728
12289376

Run 8:

37121646
45592480
37121646
45592480

Même si je peux comprendre le caractère aléatoire tant que le hashcode est constante durant le programme de durée de vie, ça me dérange qu'il n'est pas toujours aléatoire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X