是Dictionary.Last()的返回值未定义

本文关键字:返回值 未定义 Dictionary Last | 更新日期: 2023-09-27 18:09:15

今天我在阅读的一些代码中遇到了Dictionary.Last()的使用。对我来说,这是没有意义的,因为字典没有"最后"元素的明确概念。检查MSDN给了我以下信息:

为了枚举的目的,字典中的每个项都被视为表示值及其键的KeyValuePair结构。返回项的顺序未定义。

听起来好像Last()的结果也是未定义的,但是该方法实际上并没有"按顺序返回项",它暗示它根据内部顺序返回项。我可能想多了,但这是有区别的。

使用以下代码进行我自己的测试,结果每次运行测试时都一致地返回"Fifteen"。

class Program
{
    static void Main(string[] args)
    {
        Dictionary<int, string> dictionary = new Dictionary<int, string>();
        dictionary.Add(10, "Ten");
        dictionary.Add(5, "Five");
        dictionary.Add(20, "Twenty");           
        dictionary.Add(2, "Two");
        dictionary.Add(15, "Fifteen");
        Console.WriteLine(dictionary.Last());
        Console.ReadKey();
    }
}

所以现在我想知道是否可以安全地假设Dictionary.Last()返回最后一个添加的值,或者如果不应该使用该方法,因为文档说返回项的顺序未定义,而没有明确说明Last()的行为?

是Dictionary.Last()的返回值未定义

Dictionary.Last()总是返回最后添加的项的假设很容易被证明是失败的,如下所示:

var dict = new Dictionary<Guid, Guid>();
Guid a = Guid.Empty, b = a, c = a, d = a;
for (int i = 0; i < 1000; ++i)
{
    var guid = Guid.NewGuid();
    dict.Add(guid, guid);
    if (dict.Last().Key != guid)
        Console.WriteLine("Failed at iteration " + i);
    if (d != Guid.Empty)
        dict.Remove(d);
    d = c;
    c = b;
    b = a;
    a = guid;
}

因此Enumerable.Last()Dictionary一起使用的返回值是undefined

(对于Dictionary的当前实现,看起来只要您删除了一个项,那么Last()就不再返回最近添加的项。)

"我想知道假设Dictionary.Last()返回最后添加的值是否安全"

项的返回顺序未定义

它们可能按照您现在需要的顺序,但未定义的行为可能会随着内部实现的更改而随时更改。

顺序本身是由Dictionary内部定义的。因此,从当前实现来看,是确定性的,并且对于相同的输入返回相同的顺序-在您的情况下,Fifteen将始终是最后一项。但是,由于实际顺序依赖于内部实现(可能依赖于键的哈希码),您不应该依赖于此顺序,因为它不太可能是您期望的。

特别是顺序是一个实现细节。如果你依赖于此,当微软决定更改内部代码(而不是API)时,你就会遇到问题。