Что может привести к добавлению ключей к хэштебе быть нулевыми?
-
24-10-2019 - |
Вопрос
Использование .NET Micro Framework 4.1
Я добавляю следующие ключи строк (и строковые значения, не актуальные здесь) в хэштату:
"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"
При добавлении их в хэштибные ошибки не бросаются.
Однако, глядя на свойства и содержание хэштета, я вижу следующее:
16 ведра, но 6 из них имеют нулевое ключ и нулевое значение. Это всегда одно и то же.
Что может быть причиной этого?
Обновлять:
Не так много кода для публикации:
var settings = new HashTable(16);
settings.Add("eth::address", "192.168.1.1");
//Keep adding the settings mentioned above
Никаких исключений не брошено, в конце концов, в хэштате есть 16 элементов, начиная с 3 допустимых, затем несколько нулевых, затем несколько действительных и т. Д.
Нет ничего больше, так как это просто тестовый пример
Если я попытаюсь получить одну из значений, которые «потерялись», будет выброшено исключение:
var x = settings["eth::port"];
Приведет к:
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
Решение
Чтобы расширить ответ Волкана - проверка внутренней реализации Hashtable
можно найти следующее:
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;
}
Так что происходит, когда вы инициализируете его с помощью new Hashtable(16)
...? Первый, num
Значение вычисляется 16/0.72 = 22.(2)
. Анкет Затем, HashHelpers.GetPrime(22)
Впитывает, что выглядит так:
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
}
Почти готово. Нам нужно только посмотреть, что primes
является.
static HashHelpers()
{
primes = new int[] { 3, 7, 11, 17, 23 /* more values */ };
}
С 22
в качестве min
аргумент, мы можем легко увидеть GetPrime
возврат 23
. Анкет И это значение, используемое в Hashtable
Конструктор, чтобы создать массив ведра. Вы можете выполнить тот же анализ для Micro -Framework, чтобы понять, почему он создает 16 ведра (что странно TBH, учитывая, что это хорошая практика, чтобы номер ведра был основным значением).
Другие советы
У меня нет доступа к микроммеру, но для .NET 4.0 я проверил с помощью образца, который вы дали, и он выделяет 23 ведра, 7 из них имеют нулевые значения. Каждое значение помещается в ведро с его хэш -кодом % 23. Например, eth :: gateway имеет хэш -код 1866092901, а его модуль 23 - 22, поэтому он помещен в 22 -е ведро. Почему вы беспокоитесь о стратегии распределения внутреннего ведра хэш -таблиц? Попробуйте код ниже в LinqPad, и вы можете быть уверены:
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();
}