为什么在C#中不允许将'void'用作通用类型


53

哪些设计决策主张void不能构造且不允许作为泛型类型?毕竟,这只是一个特殊的空struct和本来可以避免具有不同的总PITA FuncAction代表。

(C ++允许显式void返回并允许void作为模板参数)



2
@BenVoigt尽管这里只有一个人可以(很容易地我想)给出一个正确的答案,但这并不一定需要一个人的知识。熟悉该规范的任何人都可以回答这个问题,特别是如果他们具有编程语言设计知识。这也是一个有趣的语言设计/语言实现问题,在这里成为主题。
Thomas Owens

6
@BenVoigt:为什么您如此热衷于无缘无故地提出一个完全有效且有趣的问题,而又不能满足自己的学问呢?我搜寻了一下,却找不到答案。也许这里有人读了一篇有关它的博客文章,也许做出决定的人想回答这个问题,也许有人与做出这个决定的人聊天,然后自己问问题,然后就可以继续回答。我已经停止在这个网站上发布文章了,因为人们似乎对解决问题比对回答问题更感兴趣。

4
我可以指出这里的“大重点”问题和答案,尤其是在SO上,通常是“此语法是什么意思?”的形式。这些问题几乎从未解决过,因为每个人都可以加入并提出const Poiners定义为const对象的定义。人为的原因导致一些更有趣的问题在站点之外被追捕:严重的是,某个地方的数据仓库中只有几千字节。难道我们都可以放松身心,拥抱学习,而不是强加毫无意义的随意解释的规则吗?

2
@ThomasOwens:从某种意义上说,我在这个站点上比在SO上更活跃。在该网站上,我每300个问题中就有一个答案。在SO上,我每1500个中问题都有一个答案。在SO上回答C#问题。
埃里克·利珀特

Answers:


69

“ void”的根本问题是,它与任何其他返回类型的含义不同。“ void”表示“如果此方法返回,则它根本不返回任何值。” 不为null;null是一个值。它不返回任何值。

这确实弄乱了类型系统。类型系统本质上是一个逻辑推论哪些操作对特定值有效的系统。无效的返回方法不会返回任何值,因此问题“对此内容有效的操作是什么?” 根本没有任何意义。对于有效或无效的操作,没有“事物”。

而且,这使运行时变得有些混乱。.NET运行时是虚拟执行系统的实现,该系统被指定为堆栈计算机。也就是说,根据操作对评估堆栈的影响来表征所有操作的虚拟机。(当然,实际上,该机器将在具有堆栈和寄存器的机器上实现,但虚拟执行系统仅假定一个堆栈。)从根本上说,调用void方法的效果与调用非无效方法的效果不同;非无效方法总是将某些东西放到堆栈上,这可能需要弹出。void方法永远不会在堆栈中放入任何内容。因此,在忽略方法的返回值的情况下,编译器无法将void和non-void方法视为相同。如果该方法无效,则没有返回值,因此必须没有弹出。

由于所有这些原因,“ void”不是可以实例化的类型;它没有价值,这就是重点。它不能转换为对象,并且void返回方法永远不能用非void返回方法进行多态处理,因为这样做会破坏堆栈!

因此,正如您所指出的,void不能用作类型参数,这很可惜。这将非常方便。

借助事后看来,如果一个空返回方法自动返回一个神奇的单例引用类型“ Unit”,而不是什么都没有,那么对所有相关人员会更好。然后,您将知道每个方法调用都将某些内容放入堆栈中,您将知道每个方法调用都返回可分配给对象类型变量的内容,并且当然Unit可用作类型参数,因此会有不需要具有单独的Action和Func委托类型。可悲的是,这不是我们所处的世界。

有关此方面的更多想法,请参见:


C ++支持它,而不必使用神奇的单例类型。但是我认为这与使用C#完全不同的“泛型”样式的C ++有关。
Winston Ewert

4
@WinstonEwert-我很确定C ++根本不支持泛型,但是有模板,这是根本不同的。据我了解,使用模板,编译器将进行全局搜索并用您的类型参数替换,而使用泛型,类型系统将创建适当的类型。我也认为这就是为什么C ++模板错误是如此钝的原因。我敢肯定,如果我说的话不太
对劲,

1
我认为所有结构都在编译时进行处理,以在堆栈上和内联的其他位置得到正确的放置。因此Void应该可以将其作为0个堆栈字节内的无限数量的参数进行传递。当任何结构需要转换为object或调用方法(获取this)时,将其放在堆中,并Type在内存的字段区域之前插入引用(对于许多CLR实现),因此可以被正确处理。对于我来说,类型仅仅是可以通过某些特征(字段)加以区分的一组对象。Void只是一个对象。
2012年

1
@ OlivierJacot-Descombes:如果void为空值类型,则该语句将转换为零机器码指令。对于的硬编码类型不是很有用Void,但是在类型具有多个通用参数但在某些情况下不需要某些泛型参数的情况下很有用。
超级猫

2
@EricLippert:正确处理值类型的返回值将要求能够从堆栈中弹出可变数量的单词。允许字数为零会不会有根本性的困难?如果调用方负责分配空间并传递byref,则类型系统将必须认识到空的byref没有意义,也许这不值得付出努力,但我看不到任何“基本”问题。
超级猫

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.