C# foreach 意外行为

C# foreach unexpected behavior

为什么 C# 编译器允许它编译并在 运行 时抛出 运行time 异常?

class Program
{
   static void Main(string[] args)
   {
      IEnumerable<Test> list = new List<Test>() { new Test() };

      foreach(IDisposable item in list)
      {

      }
   }
}

public class Test
{

}

这确实可以通过任何接口编译,如果您将 IDisposable 替换为具体的,它不会编译 class。

foreach 循环中有一个隐式转换。大致是这样的:

using (IEnumerator<Test> iterator = list.GetEnumerator())
{
    while (iterator.MoveNext())
    {
        IDisposable item = (IDisposable) iterator.Current;
        // Body of foreach loop here
    }
}

在泛型出现之前,这比强制转换源代码要方便得多。现在它不是那么重要,但它不编译会很奇怪。请注意,编译器 检查它是否至少 可行 。如果您使用 foreach (string item in list) 将无法编译,因为 Test 不能是 string - 但 Test 可以 是一个 IDisposable,因为它可以引用实现 IDisposableTest 的子 class 的实例。如果你将 Test class 密封,即使使用 IDisposable 也将无法编译,因为那样 Test 实例无法实现 IDisposable

基本上,如果从 Test 到迭代类型的转换可以编译,它将编译,否则将无法编译。但是如果正常转换在执行时也会失败,它也会在执行时失败。