gpt4 book ai didi

c# - 为什么 IEnumerator.Current 的错误处理不同于 IEnumerator.Current?

转载 作者:IT王子 更新时间:2023-10-29 04:19:25 26 4
gpt4 key购买 nike

我原以为对实现了 IEnumerable<T> 的空集合执行以下代码会抛出异常:

var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
var type = enumerator.Current.GetType(); // Surely should throw?

因为集合是空的,然后访问IEnumerator.Current无效,我本以为会有异常(exception)。但是,List<T> 不会抛出异常.

这是the documentation for IEnumerator<T>.Current 允许的,其中指出 Current在以下任何条件下未定义:

  • 枚举数位于集合中第一个元素之前,紧接在枚举数创建之后。在读取 Current 的值之前,必须调用 MoveNext 将枚举数推进到集合的第一个元素。
  • 最后一次调用 MoveNext 返回 false,表示结束集合。
  • 枚举器因集合中的更改(例如添加、修改或删除元素)而失效。

(我假设“未能抛出异常”可以归类为“未定义行为”...)

但是,如果您执行相同的操作但使用 IEnumerable相反,你确实得到了一个异常(exception)。此行为由 the documentation for IEnumerator.Current 指定,其中指出:

  • 如果对 MoveNext 的最后一次调用返回 false,则 Current 应该抛出 InvalidOperationException,这表明集合结束。

我的问题是:为什么会有这种差异?是否有我不知道的充分的技术原因?

这意味着看似相同的代码可能会根据是否使用 IEnumerable<T> 而表现出截然不同的行为。或 IEnumerable , 如以下程序所示(注意 showElementType1()showElementType1() 中的代码是如何相同的):

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApplication2
{
class Program
{
public static void Main()
{
var list = new List<int>();

showElementType1(list); // Does not throw an exception.
showElementType2(list); // Throws an exception.
}

private static void showElementType1(IEnumerable<int> collection)
{
var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
var type = enumerator.Current.GetType(); // No exception thrown here.
Console.WriteLine(type);
}

private static void showElementType2(IEnumerable collection)
{
var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
var type = enumerator.Current.GetType(); // InvalidOperationException thrown here.
Console.WriteLine(type);
}
}
}

最佳答案

IEnumerable<T> 的问题是那个Current类型为 T . default(T) is returned 而不是抛出异常(它是从 MoveNextRare 设置的)。

使用 IEnumerable 时你没有类型,你不能返回默认值。

实际问题是你没有检查 MoveNext 的返回值.如果它返回 false , 你不应该调用 Current .异常没关系。我认为他们发现返回 default(T) 更方便在IEnumerable<T>案例。

异常处理带来开销,返回default(T)没有(那么多)。也许他们只是认为从 Current 返回没有任何用处。 IEnumerable情况下的属性(property)(他们不知道类型)。该问题已在 IEnumerable<T> 中“解决”使用 default(T) 时.

根据这个bug report (感谢 Jesse 发表评论):

For performance reasons the Current property of generated Enumerators is kept extremely simple - it simply returns the value of the generated 'current' backing field.

这可能指向异常处理开销的方向。或者需要额外的步骤来验证 current 的值.

他们实际上只是将责任推给了foreach ,因为那是枚举器的主要用户:

The vast majority of interactions with enumerators are in the form of foreach loops which already guard against accessing current in either of these states so it would be wasteful to burn extra CPU cycles for every iteration to check for these states that almost no one will ever encounter.

关于c# - 为什么 IEnumerator.Current 的错误处理不同于 IEnumerator<T>.Current?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30840782/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com