【问题标题】:Declaring a local variable as const将局部变量声明为 const
【发布时间】:2010-06-29 13:13:08
【问题描述】:

显然,将局部变量声明为const,可以防止运行时修改。 Const 实例变量是静态的(我相信)。这对const 局部变量的性质和使用有任何影响吗? (例如线程)

【问题讨论】:

  • 如果您想要明确地描述常量字段,您最好阅读 C# 规范的第 10.4 节。这里的各种答案似乎有相当多的错误信息等等。

标签: c# constants


【解决方案1】:

“const”变量必须具有原始类型(例如 int、bool)。每当源代码中出现“const”变量时(无论是本地的还是全局的),此实例都会被 const 值本身替换。所以:

const int foo = 42;
return foo + 69;

优化后变为:

return 42 + 69

或者说:

return 111;

不存在线程问题,因为 const 变量具有原始类型并且它们仅在编译时存在。

【讨论】:

  • 这个答案有很多错误。首先,“const 变量”是矛盾的;常量永远不是变量,因为变量是存储位置,其中包含一个可以更改的值,而常量是(不是存储位置)不能更改.
  • 第二,常量不需要是“原始”类型。常量可以是任何内置值类型(int、short 等),或任何字符串常量,或任何引用类型的空引用。
  • 第三,我不明白原始类型或在编译时已知与线程有什么关系。常量不是线程安全的,“因为它们是原始类型”。常量是线程安全的因为根据定义它们不能更改,因此永远不会观察到在两个不同线程上具有不一致的值。
  • @EricLippert 我也这么认为,但我想指出的是,我认为 sthalik 的“它们仅在编译时存在”的意思是 const 名称已被优化掉并且无法区分在编译步骤中来自“文字”值。
【解决方案2】:

const 不是变量,这就是为什么它被称为常量。

【讨论】:

  • 来自维基百科“常量是一种特殊的变量”。 en.wikipedia.org/wiki/Constant_(programming)。对 OQ 中术语的懒惰使用表示歉意。
  • 一个 const 不是其原始含义的变量(即它不是变量,而是常量)。但是我很确定“const int”可以称为 const 变量。
  • @Ben:就 C# 而言,维基百科是错误的。在 C# 中,常量不是任何类型的变量。变量在 C# 中定义为内容可以变化的存储位置。常量既不是存储位置,也不能变化。
【解决方案3】:

常量不是变量,它实际上并不存储在任何地方。因为它没有被存储,所以它不是实例成员,也不是静态的。

常量只是一个值的名称。编译代码时,会将值插入到使用常量的位置。 (如果您使用在不同程序集中声明的常量,这会产生影响。更改常量的声明值不会更改使用的值,直到您重新编译使用该常量的代码。)

因此,在本地声明的常量与在其他任何地方声明的常量完全相同,只是范围不同。

【讨论】:

  • 澄清一下 - 我看到 const 被称为静态的地方不正确?
  • @Ben:是的,常量不是静态的。静态变量具有静态存储空间,而常量则根本没有存储空间。
  • @Ben,@Guffa。不,这不太对。仅仅因为常量没有关联的存储位置并不意味着它不是成员!常量字段其声明类型的成员,实际上它是静态成员。
  • @Eric:是的,常量被归类为静态成员是对的(出于某种原因),但它们不是静态存储的,这是这个问题的重点。
【解决方案4】:

我需要插话说我觉得已经给出的共识答案不完整。

冒昧地总结一下这些答案,共识是我们应该考虑以下代码不是变量声明,而是一种宏声明,其中编译器在使用标识符的地方内联 const 值:

const int foo = 42;

但是,如果使用(可能很复杂的)常量表达式声明 const “变量”,则该答案回避了出现的问题,如下所示:

const double H = 1.23e-2, Q = 7.65e-4, nu = 0.3;
const double Reynolds = H*H*H*H / Q / (1d - nu);

在这种情况下,编译器是对表达式求值一次并“存储”结果以供重复使用(如静态变量),还是在每次使用标识符时执行表达式(如C/C++ 中的#define 宏)。

在我自己的探索中,我在http://www.techopedia.com/definition/3768/constant-c 中找到了与此问题相关的以下描述:

在 C# 的上下文中,常量是一种字段或局部变量,其值在编译时设置,并且在运行时永远不能更改。它类似于变量,具有名称、值和内存位置。但是,它与变量的不同之处在于其在应用程序中只被初始化一次的特性。使用关键字“const”声明一个常量。

诚然,“内存位置”部分有点牵强——我认为它的意思是 const 值在编译期间存储在本地某处。如其他地方所述,您永远无法在代码中访问或引用此内存。否则,这似乎与我在 C# 语言规范中读到的一致:

8.5.2 局部常量声明

local-constant-declaration 声明一个或多个局部常量。

本地常量声明:

常量类型{常量声明符,}常量声明符

常量声明符:

标识符 = 常量表达式

还有:

7.19 常量表达式

constant-expression 是可以在编译时完全计算的表达式。

常量表达式:

表达式

...

只要表达式满足上面列出的要求,就会在编译时评估该表达式。即使表达式是包含非常量结构的较大表达式的子表达式也是如此。

欢迎对此“quanser”的任何反馈:^)

【讨论】:

  • 有趣的是,实际上允许 C# 编译器在编译时对常量进行求值操作,所以即使 const 做了 C++ 宏会做的事情,并在代码中的任何地方删除整个未计算的表达式,每个这些单独的表达式将在编译时计算为单个常量值。在将值放在使用的任何地方之前进行一次计算会加快 编译 时间(我确信它会这样做),但它不会影响程序的执行速度。
【解决方案5】:

由于每个方法调用都会创建自己的堆栈区域,因此拥有自己的局部变量,因此您无需担心局部变量会被其他线程修改。

AFAIK 在 c# 中将局部变量创建为 const 根本不会创建任何变量或字段,而是分配的常量值将内联放置在您在方法中使用它的任何地方。

【讨论】:

    【解决方案6】:

    在本地使用const 的主要优点是您不会意外地将标识符设置为另一个可能会改变代码正确性的值。

    【讨论】:

      【解决方案7】:

      我也把这个发到Why can't I declare a constant using var in C#?

      没有 var 的常量:

      const int Value1 = 1;
      const int Value2 = 2;
      

      带 var 的常量(匿名类型属性值创建后无法更改):

      var constants = new { 
        Value1 = 1, 
        Value2 = 2,
      };
      //use as constants.Value1
      

      【讨论】:

      • 你创建的对象不能被变异,但是你放入的变量可以被变异为完全指向另一个对象,这使得它根本不一样常量字段。
      猜你喜欢
      • 2021-08-22
      • 2021-11-28
      • 2011-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-12
      • 2021-06-03
      相关资源
      最近更新 更多