C# foreach 意外行为
C# foreach unexpected behavior
为什么 C# 编译器允许它编译并在 运行 时抛出 运行time 异常?
class Program
{
static void Main(string[] args)
{
IEnumerable<Test> list = new List<Test>() { new Test() };
foreach(IDisposable item in list)
{
}
}
}
public class Test
{
}
这确实可以通过任何接口编译,如果您将 IDisposable 替换为具体的,它不会编译 class。
foreach
循环中有一个隐式转换。大致是这样的:
using (IEnumerator<Test> iterator = list.GetEnumerator())
{
while (iterator.MoveNext())
{
IDisposable item = (IDisposable) iterator.Current;
// Body of foreach loop here
}
}
在泛型出现之前,这比强制转换源代码要方便得多。现在它不是那么重要,但它不编译会很奇怪。请注意,编译器 将 检查它是否至少 可行 。如果您使用 foreach (string item in list)
将无法编译,因为 Test
不能是 string
- 但 Test
可以 是一个 IDisposable
,因为它可以引用实现 IDisposable
的 Test
的子 class 的实例。如果你将 Test
class 密封,即使使用 IDisposable
也将无法编译,因为那样 Test
实例无法实现 IDisposable
。
基本上,如果从 Test
到迭代类型的转换可以编译,它将编译,否则将无法编译。但是如果正常转换在执行时也会失败,它也会在执行时失败。
为什么 C# 编译器允许它编译并在 运行 时抛出 运行time 异常?
class Program
{
static void Main(string[] args)
{
IEnumerable<Test> list = new List<Test>() { new Test() };
foreach(IDisposable item in list)
{
}
}
}
public class Test
{
}
这确实可以通过任何接口编译,如果您将 IDisposable 替换为具体的,它不会编译 class。
foreach
循环中有一个隐式转换。大致是这样的:
using (IEnumerator<Test> iterator = list.GetEnumerator())
{
while (iterator.MoveNext())
{
IDisposable item = (IDisposable) iterator.Current;
// Body of foreach loop here
}
}
在泛型出现之前,这比强制转换源代码要方便得多。现在它不是那么重要,但它不编译会很奇怪。请注意,编译器 将 检查它是否至少 可行 。如果您使用 foreach (string item in list)
将无法编译,因为 Test
不能是 string
- 但 Test
可以 是一个 IDisposable
,因为它可以引用实现 IDisposable
的 Test
的子 class 的实例。如果你将 Test
class 密封,即使使用 IDisposable
也将无法编译,因为那样 Test
实例无法实现 IDisposable
。
基本上,如果从 Test
到迭代类型的转换可以编译,它将编译,否则将无法编译。但是如果正常转换在执行时也会失败,它也会在执行时失败。