C# foreach 意外行为

eka*_*hev 8 c# covariance

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

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

      foreach(IDisposable item in list)
      {

      }
   }
}

public class Test
{

}
Run Code Online (Sandbox Code Playgroud)

这确实可以使用任何接口进行编译,并且如果您将 IDisposable 替换为具体类,则它不会编译。

Jon*_*eet 16

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

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

回到泛型之前,这比必须在源代码中转换要方便得多。现在它不是那么重要,但它不编译会很奇怪。请注意,编译器检查它是否至少可行。如果您使用foreach (string item in list)它,则不会编译,因为 aTest不能是 a string- 但 aTest 可以是 an IDisposable,因为它可以引用Test该 implements的子类的实例IDisposable。如果您使Test类密封,即使使用 ,它也将无法编译IDisposable,因为Test实例无法实现IDisposable

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