在下面的示例中,第一个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
}
为什么这会通过编译器? Dog
与IState
完全无关,如果我尝试遍历Cat
的列表,则编译器显然会捕获它。
答案 0 :(得分:3)
编译器正在将类型转换从元素类型隐式转换为您在foreach
语句中指定的类型。
因此,如果您有一个IEnumerable<Foo>
并将其用作:
foreach (Bar bar in foos)
然后将插入从Foo
到Bar
的转换。当且仅当该强制转换通常有效时,此函数才会编译。
将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!");
}