什么会导致添加到哈希表的键为空?

发布于 2024-11-03 15:06:20 字数 1132 浏览 2 评论 0原文

使用 .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 个有效的项目开始,然后是一些空的项目,然后是一些有效的项目,等等......

没有其他涉及,因为这只是一个测试用例

要检查的工具是 #vs2010

如果我尝试获取“丢失”的值之一, 抛出异常:

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

Using the .NET Micro Framework 4.1

I'm adding the following string keys (and string values, not relevant here) to a 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"

When adding these to the HashTable no errors are thrown.

However, when looking at the properties & content of the hashtable
I can see the following:

16 buckets, but 6 of them have a null key and null value.
It's always the same ones.

What could be causing this?

Update:

There's not much code to post:

var settings = new HashTable(16);
settings.Add("eth::address", "192.168.1.1");
//Keep adding the settings mentioned above

No exceptions are thrown, in the end there are 16
items in the hashtable, starting with 3 valid ones, then a few null ones, then a few valid ones, etc....

There's nothing else involved as this is a simply a test case

The tool to inspect is #vs2010

If I try to get one of the values that "got lost",
an exception is thrown:

var x = settings["eth::port"];

Will result in:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

噩梦成真你也成魔 2024-11-10 15:06:20

我无法访问微框架,但对于.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();
}

I don't have access to micro framework, but for .NET 4.0, i tested with sample you gave and it allocates 23 buckets, 7 of them has null values. Each value is placed in the bucket with its hash code % 23. For example, eth::gateway has hash code of 1866092901 and its modulus 23 is 22 so its placed in 22th bucket. Why do you worry about hash tables internal bucket allocation strategy? Try code below in Linqpad and you can be sure:

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();
}
情栀口红 2024-11-10 15:06:20

为了扩展 Volkan 的答案 - 检查 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 构造函数中用于创建存储桶数组的值。您可以对微框架执行相同的分析,看看它为什么创建 16 个存储桶(这很奇怪,考虑到存储桶数量为质数是一个很好的做法)。

To extend Volkan's answer - checking the internal implementation of Hashtable one might find the following:

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;
}

So what happens when you initialize it with new Hashtable(16)...? First, num's value is computed to 16/0.72 = 22.(2). Then, HashHelpers.GetPrime(22) kicks in, which looks like this:

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
}

Almost there. We only need to look up what primes is.

static HashHelpers()
{
    primes = new int[] { 3, 7, 11, 17, 23 /* more values */ };
}

With 22 as min argument, we can easily see GetPrime returns 23. And this is the value used in Hashtable constructor to create buckets array. You can perform same analysis for micro framework to see why it creates 16 buckets (which is weird TBH, considering it's good practice for buckets number to be prime value).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文