首页 > 解决方案 > C# foreach 意外行为

问题描述

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

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

      foreach(IDisposable item in list)
      {

      }
   }
}

public class Test
{

}

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

标签: c#covariance

解决方案


循环中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)that 将无法编译,因为 aTest不能是string- 但 aTest 可以是 an IDisposable,因为它可以引用Test该 implements的子类的实例IDisposable。如果您将Test类密封,即使使用 也将无法编译IDisposable,因为Test实例无法实现IDisposable

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


推荐阅读