C#foreach意外行为

时间:2019-12-18 15:01:49

标签: 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
{

}

这确实可以与任何接口一起编译,如果将IDisposable替换为具体类,则不会编译。

1 个答案:

答案 0 :(得分:12)

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 可以是{ {1}},因为它可以引用实现IDisposable的{​​{1}}子类的实例。如果将Test类密封,那么即使使用IDisposable,它也将无法编译,因为那样的话,Test实例将无法实现IDisposable

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