为什么C#中不允许使用const参数?

时间:2010-07-16 08:06:56

标签: c# language-agnostic language-design

对于C ++开发人员来说,它看起来很奇怪。在C ++中,我们将参数标记为const,以确保它的状态不会在方法中更改。还有其他C ++特定的原因,比如传递const ref以传递ref并确保状态不会被更改。但是为什么我们不能在C#中标记为方法参数const?

为什么我不能像下面那样声明我的方法?

    ....
    static void TestMethod1(const MyClass val)
    {}
    ....
    static void TestMethod2(const int val)
    {}
    ....

5 个答案:

答案 0 :(得分:57)

除了其他好的答案之外,我还要补充另一个原因,就是不要将C风格的常量放入C#中。你说:

  

我们将参数标记为const,以确保其状态不会在方法中更改。

如果const确实这样做了,那就太好了。 Const不这样做。常数是谎言!

Const并未提供我实际可以使用的任何保证。假设您有一个采用const事物的方法。代码作者有两个:编写调用者的人和编写被调用者的人。被调用者的作者使该方法采用了const。这两位作者可以假设对象是不变的吗?

无。被调用者可以自由地抛弃const并改变对象,因此调用者没有保证调用一个接受const的方法实际上不会改变它。类似地,被调用者不能假设对象的内容在被调用者的整个动作中都不会改变;被调用者可以在const对象的非const别名上调用一些变异方法,现在所谓的const对象已经更改了

C-style const不保证对象不会改变,因此被破坏。现在,C已经有了一个弱类型系统,你可以在这个系统中重新解释一个double转换为一个int,如果你真的想要的话,那么它对于const也有一个弱类型系统也就不足为奇了。但是C#被设计为具有良好的类型系统,这是一种类型系统,当你说“这个变量包含一个字符串”时,变量实际上包含对字符串的引用(或null)。我们绝对不希望将C风格的“const”修饰符放入类型系统中,因为我们不希望类型系统是谎言。我们希望类型系统 strong ,以便您可以正确地了解您的代码。

C中的Const是指南;它基本上意味着“你可以相信我不要试图改变这件事”。那应该不在类型系统; 类型系统中的内容应该是关于您可以推理的对象的事实,而不是指南

现在,不要误会我的意思;仅仅因为C中的const被深深打破并不意味着整个概念是无用的。我希望看到的是C#中的一些实际的正确的有用的形式的“const”注释,这是人类和编译器可以用来帮助他们理解代码的注释并且运行时可以用来执行自动并行化和其他高级优化之类的操作。

例如,想象一下,如果你可以在一大堆代码周围“画一个盒子”并说“我保证这个代码块在某种程度上不会对这个类的任何字段执行任何突变”这可以由编译器检查。或者画一个框,上面写着“这个方法会改变对象的内部状态,但不会以任何方式在框外观察”。这样的对象不能自动安全地多线程,但可以自动记忆。我们可以在代码上添加各种有趣的注释,以实现丰富的优化和更深入的理解。 我们可以比弱C风格的const注释做得更好。

但是,我强调这只是推测。我们没有确定的计划将此类功能纳入任何假设的未来版本的C#,如果有的话,我们还没有宣布这种方式。这是我希望看到的东西,以及即将强调多核计算可能需要的东西,但这些都不应被解释为对C#的任何特定特征或未来方向的预测或保证。

现在,如果您想要的仅仅是局部变量上的注释,该注释是一个参数,表示“此参数的值在整个方法中不会发生变化”,那么,当然,这很容易完成。我们可以支持一次初始化的“readonly”本地和参数,以及在方法中改变的编译时错误。 “using”语句声明的变量已经是一个本地变量;我们可以为所有本地和参数添加一个可选的注释,使它们像“使用”变量一样。它从未成为一个非常高优先级的功能,因此从未实现过。

答案 1 :(得分:23)

C#中没有 const correctness 的原因之一是因为它在运行时级别不存在。请记住,除非它是运行时的一部分,否则C#1.0没有任何功能。

CLR没有const正确概念的几个原因是例如:

  1. 它使运行时复杂化;此外,JVM也没有它,并且CLR基本上是作为一个项目来创建类似JVM的运行时,而不是类似C ++的运行时。
  2. 如果在运行时级别存在const正确性,那么BCL中应该有const正确性,否则就.NET Framework而言,该功能几乎没有意义。
  3. 但是如果BCL要求const正确,那么CLR之上的每种语言都应该支持const正确性(VB,JavaScript,Python,Ruby,F#等)。会发生。< / LI>

    Const正确性几乎是C ++中仅存在的语言特性。因此,它几乎归结为同样的论证,即为什么CLR不需要检查异常(这是一种仅Java语言的特性)。

    另外,我认为您不能在托管环境中引入这种基本类型系统功能而不会破坏向后兼容性。因此,不要指望进入C#世界的const正确性。

答案 2 :(得分:11)

我认为有两个原因C#不是const-correct。

第一个是可理解性。很少有C ++程序员理解const正确性。 const int arg的简单示例很可爱,但我也看到char * const * const arg - 一个常量指针指向非常量字符的常量指针。指向函数的指针的正确性是一个全新的混淆程度。

第二个是因为类参数是通过值传递的引用。这意味着已经有两个级别的常量要处理,没有明显清晰的语法。类似的绊脚石是集合(以及集合的集合等)。

Const-correctness是C ++类型系统的重要组成部分。从理论上讲,它可以添加到C#中,只能在编译时检查(它不需要添加到CLR中,除非包含const成员方法的概念,否则不会影响BCL)

但是,我认为这不太可能:第二个原因(语法)很难解决,这将使第一个原因(可理解性)更加成为一个问题。

答案 3 :(得分:5)

const在C#中的意思是“编译时常量”,而不是像C ++那样“只读”但可能是其他代码可变的“。 C#中C ++ const的粗略模拟是readonly,但是那个仅适用于字段。除此之外,没有C ++ - 就像C#中的const正确概念一样。

理由很难说清楚,因为有很多潜在的原因,但我的想法是希望首先保持语言的简单性,以及实现这一点的不确定优势。

答案 4 :(得分:5)

从C#7.2(与Visual Studio 2017 15.5一起于2017年12月)开始,这是可能的。

仅适用于结构和基本类型!,不适用于类成员。

您必须使用in来将参数作为参考输入发送。参见:

请参阅: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier

以您的示例为例:

....
static void TestMethod1(in MyStruct val)
{
    val = new MyStruct;  // Error CS8331 Cannot assign to variable 'in MyStruct' because it is a readonly variable
    val.member = 0;  // Error CS8332 Cannot assign to a member of variable 'MyStruct' because it is a readonly variable
}
....
static void TestMethod2(in int val)
{
    val = 0;  // Error CS8331 Cannot assign to variable 'in int' because it is a readonly variable
}
....