KFL*_*KFL 1 c# foreach typechecking
我对这个问题有类似的问题.而是我的SomeClass工具SomeInterface.在这种情况下,即使我标记SomeClass为sealed,编译器时间类型检查仍然没有启动.例如下面.
编译器类型检查对我来说很重要,因为我正在重构一个大项目,将枚举源(source在a中foreach (SomeClass foo in source))更改IEnumerable<SomeClass>为IEnumerable<SomeInterface>.有时我忘记将循环中的枚举器类型声明更改SomeClass为SomeInterface,并且项目仍然编译.那会破坏事情真的很糟糕!!
请注意,我无法将循环变量类型更改为隐式,var因为它正在退出代码库.但我能够更改接口的声明及其具体的实现类.
class Program
{
static void Main(string[] args)
{
IEnumerable<SomeInterface> someFoos = new SomeInterface[] { new SomeOtherClass(), new SomeOtherClass(), new SomeOtherClass() };
foreach (SomeClass foo in someFoos)
{
foo.ToString(); // runtime InvalidCastException
}
}
}
interface SomeInterface { }
sealed class SomeClass : SomeInterface
{
public override string ToString()
{
return "SomeClass";
}
}
class SomeOtherClass : SomeInterface
{
public override string ToString()
{
return "SomeOtherClass";
}
}
Run Code Online (Sandbox Code Playgroud)
您在一个问题中提出了两个问题.几乎总是如此,你已经回答了你的两个问题之一.将来,考虑每个问题提出一个问题; 你更有可能回答你的问题.
我会回答你的第一个问题.
问题1:为什么编译器不会出错,因为循环变量的类型与源枚举的元素类型不兼容?
这是一个"为什么不"的问题,很难回答"为什么不"的问题; 他们预先假定世界应该是一种不同的方式,并问为什么不是.实际上,为什么世界不是你想要的那样,有无数的理由.我的建议是你不要再问"为什么不呢?" 问题在这里.相反,尝试询问有关世界的问题.
所以让我澄清这个问题.我们有
foreach(X item in collection)
Run Code Online (Sandbox Code Playgroud)
哪个collection是序列Y.
问题:
X和之间的关系必须Y是什么?
Y必须明确可转换为X.也就是说,表单的强制转换操作符(X)必须合法才能应用于类型的项目Y.
这是少见的情况之一,其中C#将代表您自动插入强制转换操作,而代码中不会显示强制转换操作符.
问题:哪种语言设计原则表明这种情况应该是罕见的?
C#被设计为静态检查的类型安全语言; 此转换将类型检查移动到运行时而不是编译时,从而降低了安全性.
问题:语言设计决策需要在竞争原则之间进行权衡.导致C#设计团队在语言中包含"隐形"演员的令人信服的场景是什么?
foreach循环的语义是在将泛型添加到语言之前开发的.这意味着序列可能是IEnumerable,因此将是一系列objects.但是用户可能知道特定序列是所有字符串.因此,在C#1.0中,此代码非常常见:
foreach(object item in collection)
{
string s = (string)item;
...
Run Code Online (Sandbox Code Playgroud)
这似乎是不必要的冗长.因此,语言设计团队决定允许转换为循环变量类型.
有人可能会合理地指出,这会增加您发现的错误的可能性.另一个特性可能是转换仅在转换时发生object.可能还有其他设计选择.C#设计团队选择明确转换,这就是我们必须接受的.
在反事实的世界中,从第一天开始就可以获得通用收藏品,设计可能会有所不同.但是那种反事实的推理并不是很有效率.