gpt4 book ai didi

c# - 即使枚举类型被密封,foreach 也不会进行类型检查

转载 作者:太空宇宙 更新时间:2023-11-03 17:24:25 25 4
gpt4 key购买 nike

我有一个与 this question 类似的问题.但是我的 SomeClass工具 SomeInterface .在这种情况下,即使我标记 SomeClass作为sealed ,编译器时间类型检查仍然没有启动。示例如下。

问题 1:为什么编译器不会报错,因为循环变量的类型与源可枚举的元素类型不兼容?

进行编译器类型检查对我来说很重要,因为我正在重构一个大项目,将枚举源(source 中的 foreach (SomeClass foo in source))从 IEnumerable<SomeClass> 更改为至 IEnumerable<SomeInterface> .有时我忘记更改循环中的枚举器类型声明 SomeClassSomeInterface ,并且该项目仍在编译。那会把事情搞砸的!!

问题 2:为了使这种重构类型安全,您有什么建议?

请注意,我无法将循环变量类型更改为隐式 var因为它正在退出代码库。但是我可以更改接口(interface)的声明及其具体实现类。

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";
}
}

最佳答案

你在一个问题中问了两个问题。正如几乎总是发生的那样,您已经回答了两个问题之一。将来,考虑每个问题问一个问题;您的问题更有可能得到解答。

我会回答你的第一个问题。

Question 1: Why wouldn't the compiler give an error as the type of the loop variable isn't compatible with the type of elements of the source enumerable?

这是一个“why not”的问题,很难给出“why not”问题的答案;他们假定世界应该是不同的方式,并问为什么不是这样。世界并非如你所愿,原因有无数。我的建议是你不要再问“为什么不呢?”问题在这里。相反,尝试询问有关世界是怎样的的问题。

所以让我澄清一下这个问题。我们有

foreach(X item in collection)

其中 collectionY 的序列。

Question: what must the relationship between X and Y be?

Y 必须显式转换为X。也就是说,(X) 形式的转换运算符必须合法才能应用于 Y 类型的项目。

这是一种罕见的情况,在这种情况下,C# 将代表您自动插入一个强制转换操作,而无需在代码中显示强制转换运算符。

Question: What language design principles suggest that this situation ought to be rare?

C# 被设计成一种静态检查类型安全的语言;这种转换将类型检查移至运行时而不是编译时,从而降低了安全性。

Question: Language design decisions require making tradeoffs between competing principles. What was the compelling scenario that caused the C# design team to include an "invisible" cast in the language?

foreach 循环的语义是在将泛型添加到语言之前开发的。这意味着序列很可能是 IEnumerable,因此是 object 的序列。但是用户可能知道一个特定的序列是,比方说,所有的字符串。因此,在 C# 1.0 中,这段代码将极为常见:

foreach(object item in collection)
{
string s = (string)item;
...

这似乎不必要地冗长。因此语言设计团队决定允许显式转换为循环变量类型。

有人可能会合理地注意到,这增加了您发现的错误的可能性。另一个功能可能是说只有从 object 转换时才会发生转换。可能还有其他设计选择。 C# 设计团队选择显式转换,这就是我们必须接受的。

在通用集合从一开始就可用的反事实世界中,设计可能会有所不同。但这种反事实推理并不是很有成效。

关于c# - 即使枚举类型被密封,foreach 也不会进行类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29611556/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com