C#编译器为何未在foreach循环中触发预期编译错误?
为何foreach中泛型转换仅给出提示而非触发编译错误?
先看第一个存在疑问的代码案例:
IList<IList<double>> xs = new List<IList<double>> { new List<double> { 2 } }; IList<string> x0 = xs.First(); // 如预期无法编译 foreach (IList<string> x in xs) { } // 意外可编译!
尽管编译通过,Visual Studio仍会提示第3行存在“可能在运行时失败的隐式转换”。
再看对比案例,编译器能正确检测所有错误:
IList<double> xs = new List<double> { 2 }; string x0 = xs.First(); // 如预期无法编译 foreach (string x in xs) { } // 如预期无法编译
核心差异在于C#编译器对直接赋值和foreach循环变量赋值的转换规则不同:
- 直接赋值场景(比如
IList<string> x0 = xs.First()):要求两种类型之间必须存在隐式引用转换。但IList<double>和IList<string>是不兼容的泛型接口,不存在任何隐式转换关系,因此直接触发编译错误。 - foreach循环场景:编译器允许使用显式引用转换将集合元素类型转换为循环变量类型。因为
IList<double>和IList<string>都是引用类型,语法上允许显式转换(哪怕运行时必然失败),所以编译能通过。但编译器能识别出这个转换在运行时肯定会抛出InvalidCastException,因此会给出警告提示。
而第二个案例中,double是值类型,string是引用类型,两者之间既没有隐式转换,也不存在合法的显式引用转换,所以不管是直接赋值还是foreach循环,都会触发编译错误。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

