foreach(Derived obj in new List <Base>())

Ste*_*nov 5 c# syntax polymorphism foreach inheritance

以下代码有什么作用?

class Base { }
class Derived : Base { }
class Test
{
    void Foo(List<Base> list)
    {
        foreach (Derived obj in list)
        {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我没想到它甚至可以编译,但确实如此.

Dir*_*mar 10

您正在观察的行为是根据第8.8.4节C#语言规范的foreach语句.本节定义foreach语句的语义如下:

[...]上述步骤,如果成功,则明确地生成集合类型C,枚举器类型E和元素类型T.一个foreach形式的声明

foreach (V v in x) embedded-statement
Run Code Online (Sandbox Code Playgroud)

然后扩展到:

{
    E e = ((C)(x)).GetEnumerator();
    try {
        V v;
        while (e.MoveNext()) {
            // here the current item will be casted                
            v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        // Dispose e
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器插入此显式转换的原因是历史性的.C#1.0没有泛型,所以为了允许像这样的简单代码

ArrayList list = new ArrayList();
list.Add(1);
foreach (int i in list)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

决定让编译器引入演员阵容.


Ran*_*pho 7

绝对没有,但它以非常低效的方式做到了.

操作顺序如下:

  1. 实例化新列表,零项
  2. 迭代新实例化的列表,该列表没有项目
  3. 不将Base对象强制转换为Derived对象,因为列表中没有项目.如果列表包含任何项,则此步骤将导致运行时异常.
  4. 不执行foreach块中的代码,因为列表中没有项目.

编辑
根据您的编辑,您将冒着InvalidCastException传递列表的任何元素的风险,Foo实际上不是Derived对象.

Edit2
为什么要编译?因为foreach涉及Object列表中每个项的隐式强制转换foreach,所以在这种情况下,另一个显式强制转换为块中的指定类型Derived

  • 对,谢谢.请改变你的答案,只要说出"Foreach attemts,默默地将每个项目向下转移到Derived,然后在不可能的情况下抛出". - 然后它会完全回答我的问题,我将能够接受. (2认同)