为什么这种隐式转换不会导致编译时错误?

Why does this implicit cast not result in compile-time error?

只是想了解 C#。仅考虑以下简化示例。

void Main()
{
    IList<IAnimal> animals = new List<IAnimal>
    {
        new Chicken(),
        new Cow(),
    };

    // Shouldn't this line result in a compile-time error?
    foreach (Chicken element in animals)
    {
    }
}

public interface IAnimal
{
}

public class Cow : IAnimal
{
}

public class Chicken : IAnimal
{
}

虽然第一次迭代成功,但第二次没有。老实说,我预计这会在编译时失败。有谁知道为什么它只在运行时失败?

因为 foreach 语句在 C# Language Specification 中定义有一个(隐藏的)显式转换:

The above steps, if successful, unambiguously produce a collection type C, enumerator type E and element type T. A foreach statement of the form

foreach (V v in x) embedded-statement

is then expanded to:

{
    E e = ((C)(x)).GetEnumerator();
    try {
        while (e.MoveNext()) {
            V v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        … // Dispose e
    }
}

(注意 (V)(T)e.Current,"explicit" 转换为类型 V

不幸的是,它是这样定义的,因为这是您在 C# 1 中真正需要的(在泛型之前,您希望在 foreachobject) 的集合,现在,为了向后兼容,它不能更改。