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

时间:2018-07-11 08:38:28

标签: c# c#-4.0 compiler-errors

在下面的示例中,第一个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的列表,则编译器显然会捕获它。

1 个答案:

答案 0 :(得分:3)

编译器正在将类型转换从元素类型隐式转换为您在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

在您的收藏示例中:

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