为什么C#没有像C++那样的常量性(constness)?

14

C# 中的引用与 C++ 中的引用相似,但不同之处在于它们受到垃圾回收的控制。

那么,为什么 C# 编译器很难支持以下内容呢?

  1. 被标记为 const 的成员函数。
  2. 被标记为 const 的数据类型(除了字符串),只能通过该类型的 const 成员函数进行调用的引用?

我相信如果 C# 支持这个功能将非常有用。首先,它可以帮助那些似乎普遍存在的 C# 程序员返回裸指向私有数据的行为。

或者在 C# 中已经有类似的东西了吗?(我知道有关 readonlyconst 关键字,但它们并不能真正满足上述目的)

5个回答

17
我怀疑有一些实际原因和一些理论原因:
  • const关键字应该应用于对象还是引用?如果是引用,这应该只在编译时生效,还是作为引用本身的一部分?其他拥有对同一对象的非const引用的东西是否可以在底层进行操作?
  • 你是否希望能够像在C++中那样去除const?在托管平台上,这听起来不像是你想要的东西...但在C++中,有没有那些情况下它是有意义的?
  • 当一个声明涉及多个类型时,语法变得棘手(在我看来)- 想想数组、泛型等等。很难确定哪一部分是const。
  • 如果你不能去除const,那么每个人都必须做正确的事情。换句话说,.NET框架类型和你使用的任何其他第三方库都必须做正确的事情,否则你的代码由于constness的微妙问题而无法正常工作。

然而,有一个重要的原因解释为什么它现在不能被支持:

  • 向后兼容性:没有办法将所有库正确迁移到它上面,所以它几乎没有用处 :(

我同意有一种常量指示器会很有用,但我恐怕不会发生这种情况。

编辑:在Java社区中,关于这个问题已经争论了很长时间。你可能会对相关错误上的许多评论感兴趣。


谢谢Jon。这很有启发性。 - Frederick The Fool

6

正如Jon所说(当然),const正确性并不像看起来那么简单。C++有自己的做法,D语言也有另一种(可以说更正确/有用)的方式。C#也在尝试,但没有做出更大胆的尝试,就像你发现的那样(正如Jon再次详细介绍的那样)。

话虽如此,我认为许多Jon提到的“理论原因”在D语言的模型中得到了解决。

在D语言(2.0)中,const的工作方式与C++类似,但它是完全可传递的(因此应用于指针的const将应用于所指向的对象、该对象的任何成员、该对象拥有的任何指针、它们所指向的对象等) - 但明确指出这仅适用于您声明为const的变量(因此,如果您已经有一个非const对象,并且您使用const指针指向它,则非const变量仍然可以改变状态)。

D引入了另一个关键字-invariant-它适用于对象本身。这意味着一旦初始化,任何东西都不能改变状态。

这种安排的美妙之处在于,const方法可以接受const和invariant对象。由于invariant对象是函数式世界的基础,因此const方法可以在函数式意义上标记为“纯”-即使它可能与可变对象一起使用。

回到正题-我认为我们现在(00年代后半期)才刚刚了解如何最好地使用const(和invariant)。当时.Net的定义还不够明确,因此没有做出太多承诺-现在来改装已经太晚了。

不过,我很想看到D语言的移植版本运行在.Net VM上 :-)


5

有趣,我之前没有看到过。不过,我认为从函数的角度来看(正如我在回复中提到的),这使得任何困难都是值得的。 - philsquared

2

如果将不可变类型加入C#的未来版本,我也不会感到惊讶。

实际上,C# 3.0已经朝着这个方向迈出了一步。例如,匿名类型就是不可变的。

我认为,在为并行设计的扩展的推动下,我们很可能会越来越频繁地看到不可变性出现。


0
问题是,我们在C#中需要const吗?
  1. 我很确定JITter知道给定的方法不会影响对象本身,并自动执行相应的优化。(也许通过发出call而不是callvirt?)

  2. 我不确定我们需要这些,因为constness的大部分优点都与性能有关,最终你将回到第1点。

除此之外,C#还有readonly关键字。


1
我不同意你的说法,即“const性最重要的优点大多与性能有关” - 我认为其中大多数与正确性和可维护性有关。 - Jon Skeet
2
这不是为了JITter的方便,而是为了程序员。在C++中,如果我试图更改const对象,编译器会给出错误。因此,例如,我可以从我的方法返回const引用。在C#中,似乎每个人都返回任何人都可以更改的引用。危险! - Frederick The Fool

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接