Quelles sont les causes clés ajoutées à une Hashtable être nulle?
-
24-10-2019 - |
Question
Utilisation du .NET Micro Framework 4.1
J'ajoute les clés de chaîne suivantes (et les valeurs de chaîne, pas pertinente ici) à un Hashtable:
"eth::address"
"eth::netmask"
"eth::gateway"
"eth::dns"
"eth::port"
"com::baudrate"
"com::parity"
"com::databits"
"com::stopbits"
"com::handshake"
"com::read-timeout"
"com::write-timeout"
"drv::led-firmware-file"
"scr::width"
"scr::height"
"scr::colors"
Lors de l'ajout de ces au
Hashtable aucune erreur sont jetés.Cependant, lorsque l'on examine les propriétés et le contenu de la table de hachage Je peux voir ce qui suit:
16 seaux, mais 6 d'entre eux ont une clé nulle et la valeur null. Ce sont toujours les mêmes.
Qu'est-ce que pourrait être la cause?
Mise à jour:
Il n'y a pas beaucoup de code à message:
var settings = new HashTable(16);
settings.Add("eth::address", "192.168.1.1");
//Keep adding the settings mentioned above
exceptions sont jetés Non, à la fin il y a 16 articles dans la table de hachage, en commençant par 3 les valides, quelques unes nuls, puis quelques unes valides, etc ....
Il n'y a rien d'autre impliqué que cela est simplement un test
Si je tente d'obtenir l'une des valeurs qui « se sont perdues », une exception est levée:
var x = settings["eth::port"];
généreront:
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
An unhandled exception of type 'System.Exception' occurred in mscorlib.dll
enter code here
La solution
Pour prolonger la réponse de Volkan - vérifier la mise en œuvre interne d'une Hashtable
pourrait trouver ce qui suit:
public Hashtable(int capacity) : this(capacity, (float) 1f)
{
}
public Hashtable(int capacity, float loadFactor)
{
// arguments checking - elided
this.loadFactor = 0.72f * loadFactor;
double num = ((float) capacity) / this.loadFactor;
if (num > 2147483647.0)
{
throw new ArgumentException(
Environment.GetResourceString("Arg_HTCapacityOverflow"));
}
int num2 = (num > 3.0) ? HashHelpers.GetPrime((int) num) : 3;
this.buckets = new bucket[num2];
this.loadsize = (int) (this.loadFactor * num2);
this.isWriterInProgress = false;
}
Alors qu'est-ce qui se passe lorsque vous initialisez avec new Hashtable(16)
...? Tout d'abord, la valeur de num
est calculée à 16/0.72 = 22.(2)
. Puis, coups de pied dans HashHelpers.GetPrime(22)
, qui ressemble à ceci:
internal static int GetPrime(int min)
{
// arguments checking - elided
for (int i = 0; i < primes.Length; i++)
{
int num2 = primes[i];
if (num2 >= min)
{
return num2;
}
}
// more code; irrelevant in this case - elided
}
On y est presque. Nous avons seulement besoin de regarder ce que primes
est.
static HashHelpers()
{
primes = new int[] { 3, 7, 11, 17, 23 /* more values */ };
}
Avec 22
comme argument min
, nous pouvons facilement voir les rendements de GetPrime
23
. Telle est la valeur utilisée dans le constructeur de Hashtable
pour créer tableau des seaux. Vous pouvez effectuer même analyse pour cadre micro pour voir pourquoi il crée 16 seaux (qui est TBH bizarre, étant donné qu'il est une bonne pratique pour le nombre de seaux pour être la valeur de choix).
Autres conseils
Je n'ai pas accès à cadre micro, mais pour .NET 4.0, je l'ai testé avec un échantillon que vous avez donné et il alloue 23 seaux, 7 d'entre eux a des valeurs nulles. Chaque valeur est placée dans le seau avec son code de hachage% 23. Par exemple, eth :: passerelle a le code de hachage de 1866092901 et son module 23 est 22 donc sa place dans le seau 22. Pourquoi vous inquiétez-vous sur les tables de hachage stratégie interne d'allocation de seau? Essayez le code ci-dessous dans LINQPad et vous pouvez être sûr:
void Main()
{
string[] vals = {"eth::address", "eth::netmask", .. all other strings... };
var ht = new Hashtable(16);
foreach (var v in vals)
ht[v] = v;
var m = typeof(Hashtable).GetField("buckets", BindingFlags.NonPublic | BindingFlags.Instance);
m.GetValue(ht).Dump();
ht.Dump();
}