为什么我可以(几乎)在不相关接口列表的 foreach 中使用任何类型?

Why can I use (almost) any type in a foreach over a list of unrelated interfaces?

对于下面示例中的第一个 foreach,我确定它应该会引发编译错误,但它们构建良好。问题只发生在 运行 时间,当它抛出无效的转换异常时(如您所料):

public interface IState
{
    int Id { get; }
    string Description { get; }
}

public class Dog
{
    public string Name { get; set; }
    public string Breed { get; set; }
}

public class Cat
{
    public string Name { get; set; }
    public string Breed { get; set; }
}

public void Foo()
{
    IEnumerable<IState> states = new List<IState>();
    foreach (Dog dog in states) { } // Does not break in the compiler

    IEnumerable<Cat> cats = new List<Cat>();
    foreach (Dog dog in cats) { } // Obviously breaks in compiler
}

为什么这会通过编译器? DogIState 完全无关,如果我尝试遍历 Cat 的列表,那么编译器显然会捕获它。

编译器正在隐式地将强制转换从元素类型转换为您在 foreach 语句中指定的类型。

因此,如果您有 IEnumerable<Foo> 并将其用作:

foreach (Bar bar in foos)

然后将插入一个从 FooBar 的转换。当且仅当该转换通常有效时,这才会编译。

Cat 转换为 Dog 无效,因为它们是不相关的类型。 Cat 引用可以 永远不会 作为 Dog 引用有效。

如果 IState 转换为 Dog 是有效的,因为它 可能 是有效的:

public class DogState : Dog, IState
{
    public int Id => 5;
    public string Description => "Dog state!";
}

IState state = new DogState();
Dog dog = (Dog) state; // Won't throw

在您的 collection 示例中:

IEnumerable<IState> states = new List<IState> { new DogState() };
foreach (Dog dog in states)
{
    Console.WriteLine("I've got a dog state!");
}