什么可以导致添加到Hashtable的键为空?

时间:2011-04-27 13:54:44

标签: c# .net .net-micro-framework

使用.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"

将这些添加到HashTable时,不会抛出任何错误。

然而,在查看属性时哈希表的内容 我可以看到以下内容:

16个桶,但其中6个具有空键和空值。 它总是一样的。

可能导致这种情况的原因是什么?

更新

发布的代码不多:

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

没有抛出异常,最终有16个 哈希表中的项目,从3个有效的项目开始,然后是几个空的项目,然后是一些有效的项目......等等。

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

The tool to inspect is #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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

要扩展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个桶(这是奇怪的TBH,考虑到桶数是优质值的好习惯)。