tl; dr对于具有文字值的局部变量,const
完全没有区别。
您对“内部方法”的区分非常重要。让我们看一下,然后将其与const
字段进行比较。
常量局部变量
局部变量的唯一好处const
是无法重新分配该值。
但是const
仅限于基本类型(int
,double
...)和string
,这限制了其适用性。
题外话:C#编译器提出了一些建议,以允许使用“只读”局部变量(此处)的更一般概念,从而将这种优势扩展到其他场景。他们可能不会被认为是const
,虽然,很可能有这样的声明不同的关键字(即let
或readonly var
或类似的东西)。
考虑以下两种方法:
private static string LocalVarString()
{
var s = "hello";
return s;
}
private static string LocalConstString()
{
const string s = "hello";
return s;
}
在内置Release
模式下,我们看到以下(删节的)IL:
.method private hidebysig static string LocalVarString() cil managed
{
ldstr "hello"
ret
}
.method private hidebysig static string LocalConstString() cil managed
{
ldstr "hello"
ret
}
如您所见,它们都产生完全相同的IL。本地s
是否const
没有影响。
原始类型也是如此。这是一个使用示例int
:
private static int LocalVarInt()
{
var i = 1234;
return i;
}
private static int LocalConstInt()
{
const int i = 1234;
return i;
}
再次,IL:
.method private hidebysig static int32 LocalVarInt() cil managed
{
ldc.i4 1234
ret
}
.method private hidebysig static int32 LocalConstInt() cil managed
{
ldc.i4 1234
ret
}
因此,我们再次看到没有区别。这里不能有性能或内存差异。唯一的区别是开发人员无法重新分配该符号。
常量字段
将const
字段与可变字段进行比较是不同的。非常量字段必须在运行时读取。因此,您最终会遇到这样的IL:
ldc.i4 1234
ldsfld int32 MyProject.MyClass::_myInt
显然,假设JIT本身不能内联常量值,那么这将如何导致性能差异。
这里的另一个重要区别是在程序集之间共享的公共const字段。如果一个程序集公开了一个const字段,而另一个程序集则使用了它,则在编译时将复制该字段的实际值。这意味着,如果包含const字段的程序集已更新,但使用的程序集未重新编译,则将使用旧的(可能不正确的)值。
常量表达式
考虑以下两个声明:
const int i = 1 + 2;
int i = 1 + 2;
对于const
表单,加法必须在编译时计算,这意味着数字3保留在IL中。
对于非const
格式,编译器可以自由地在IL中发出加法运算,尽管JIT几乎可以肯定会应用基本的常量折叠优化,因此生成的机器代码将是相同的。
的C#7.3的编译器发出ldc.i4.3
操作码为两个以上表达式。
const
。它不会为编译器提供任何其他信息。检查此答案以获取更多详细信息。