为什么我可以(几乎)在不相关接口列表的 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
}
为什么这会通过编译器? Dog
与 IState
完全无关,如果我尝试遍历 Cat
的列表,那么编译器显然会捕获它。
编译器正在隐式地将强制转换从元素类型转换为您在 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
在您的 collection 示例中:
IEnumerable<IState> states = new List<IState> { new DogState() };
foreach (Dog dog in states)
{
Console.WriteLine("I've got a dog state!");
}
对于下面示例中的第一个 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
的列表,那么编译器显然会捕获它。
编译器正在隐式地将强制转换从元素类型转换为您在 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
在您的 collection 示例中:
IEnumerable<IState> states = new List<IState> { new DogState() };
foreach (Dog dog in states)
{
Console.WriteLine("I've got a dog state!");
}