关于C#:谁在字典First()?

Who's on Dictionary<>.First()?

本问题已经有最佳答案,请猛点这里访问。

当您在Dictionary集合的实例上调用.NET 3.5扩展方法Enumerable.First()时,它的含义是什么?

键集是确定哪个项是第一个项,还是只是未定义?


好吧,我相信这组键将决定哪个项目是第一个,但不是以一种定义明确(或易于预测)的方式。换句话说,不要假定它总是以相同的方式工作——它和依赖于运行之间保持相同的哈希代码实现一样不安全。

编辑:我相信事实上,插入的顺序确实很重要,与我以前的想法相反。但是,这是特定于实现的(因此在下一个版本中很容易更改)。我相信,在当前的实现中,如果没有删除第一个条目,那么添加的第一个条目将是返回的第一个条目。如果删除了添加的第一个条目,则顺序将被破坏,而不是删除最早的条目。下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;

class Test
{
    static void Main(string[] args)
    {
        var dict = new Dictionary<int, int>();        
        dict.Add(0, 0);
        dict.Add(1, 1);
        dict.Add(2, 2);
        dict.Remove(0);
        dict.Add(10, 10);

        foreach (var entry in dict)
        {
            Console.WriteLine(entry.Key);
        }
        Console.WriteLine("First key:" + dict.First().Key);
    }
}

结果是10、1、2和"first key:10"-显示最后添加的条目将首先返回。

然而,我想再次强调,框架的各个版本之间的一切都可能发生变化。


我在查看一些代码,这些代码使用foreach循环获取字典对象中的"第一"项。代码假定这是第一个添加到字典中的代码。

最初我认为dictionary.first()方法会更有效。但后来我意识到,在这种情况下,什么项目是第一个的整个概念可能没有多大意义。

Echilon建议,SortedDictionary的开销和功能可能比我需要的要多。我倾向于保存添加的第一个元素的键。


如果你需要字典中的第一个条目,最好使用SortedDictionary。我认为第一个()方法只返回第一个恰好位于顶部的项,但不一定返回第一个添加的项。


未指定实现Dictionary的类中Keys集合的顺序。所以你不知道First()会有什么回报。

但无论如何,还是有理由使用First(),或者更具体地说,使用FirstOrDefault()。如果您有一个方法接受一个IEnumerable参数,并且您知道t是一个类型,它的默认值是null, your method can usefirstordefault()`来测试对象是否为空。

为什么你不使用Count()?利用延期执行。如果在生成器上调用FirstOrDefault(),生成器将产生一个结果并停止。如果在生成器上调用Count(),则生成器必须枚举到列表的末尾。

所以你可以写一个这样的函数:

1
2
3
4
bool ListIsEmpty(IEnumerable<string> list)
{
    return list.FirstOrDefault() == null;
}

像这样使用:

1
2
3
4
5
6
7
8
if (!ListIsEmpty(dict.Keys))
{
    Console.WriteLine("Dictionary is not empty");
}
if (!ListIsEmpty(dict.Keys.Where(x => x.Contains("foo"))
{
    Console.WriteLine("Dictionary has at least one key containing 'foo'.");
}

并且要知道,为了做出这些决定,代码正在做它必须做的最起码的事情。

编辑:

我应该指出,上面代码所做的另一个假设是:IEnumerable的第一项没有空值!

当在其中一个集合上运行时,它总是为Keys字典集合或DataRowCollection(我对linq的主要用例)或Where()集合提供保证。

但是对于一个List或者一个List来说,这是没有保证的。因此,在某些情况下,在使用FirstOrDefault()之前,您肯定需要三思而后行。


我做了更多的挖掘,发现msdn警告说字典中的值和键的顺序是未知的。所以我相信这意味着first()可能不会总是返回与添加更多值相同的值。