每当我在方法中有局部变量时,ReSharper建议将它们转换为常量:
// instead of this:
var s = "some string";
var flags = BindingFlags.Public | BindingFlags.Instance;
// ReSharper suggest to use this:
const string s = "some string";
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
鉴于这些是真正的常量值(而不是变量)我理解ReSharper建议将它们更改为const。
但除此之外,使用const(例如更好的性能)是否有任何其他优势可以证明使用const BindingFlags
代替方便且可读的var
关键字?
顺便说一句:我刚刚在这里发现了一个类似的问题:Resharper always suggesting me to make const string instead of string,但我认为这更多是关于一个类的字段,我的问题是关于局部变量/ consts。
答案 0 :(得分:81)
如果您尝试将值分配给常量,编译器将抛出错误,从而可能会阻止您意外更改它。
此外,通常使用常量与变量有一个小的性能优势。这与它们编译为MSIL的方式有关,符合this MSDN magazine Q&A:
现在,无论在代码中引用myInt,而不是必须执行“ldloc.0”来从变量中获取值,MSIL只需加载硬编码到MSIL中的常量值。 因此,使用常量通常具有较小的性能和内存优势。但是,为了使用它们,您必须在编译时具有变量的值,并且在编译时对该常量的任何引用即使他们在不同的集会中,也会进行这种替换。
如果在编译时知道值,常量肯定是一个有用的工具。如果不这样做,但想确保您的变量只设置一次,则可以使用C#中的readonly关键字(映射到MSIL中的initonly)来指示变量的值只能在构造函数中设置;在那之后,改变它是一个错误。这通常在字段有助于确定类的标识时使用,并且通常设置为等于构造函数参数。
答案 1 :(得分:18)
tl; dr ,const
完全没有区别。
你对"内部方法的区分"非常重要。让我们看一下,然后将其与const
字段进行比较。
const
局部变量的唯一好处是无法重新分配该值。
但const
仅限于基本类型(int
,double
,...)和string
,这限制了它的适用性。
题外话:有人建议C#编译器允许更一般的概念' readonly'本地人(here)会将此优势扩展到其他方案。它们可能不会被视为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
字段与变量字段进行比较不同。必须在运行时读取非const字段 。所以你最终得到这样的IL:
// Load a const field
ldc.i4 1234
// Load a non-const field
ldsfld int32 MyProject.MyClass::_myInt
很明显,如果JIT无法内联一个恒定值,这会导致性能差异。
此处的另一个重要区别是跨程序集共享的公共const字段。如果一个程序集公开const字段,而另一个程序集使用它,那么该字段的实际值将在编译时复制。这意味着如果更新包含const字段的程序集但不重新编译using程序集,则将使用旧的(可能不正确的)值。
考虑这两个声明:
const int i = 1 + 2;
int i = 1 + 2;
对于const
形式,必须在编译时计算加法,这意味着数字3保存在IL中。
对于非const
形式,编译器可以自由地在IL中发出加法运算,尽管JIT几乎肯定会应用基本的常量折叠优化,因此生成的机器代码将是相同的。
答案 2 :(得分:14)
根据我的理解,Const值在运行时不存在 - 即以存储在某些存储器位置的变量的形式 - 它们在编译时嵌入在MSIL代码中。因此会对性能产生影响。在变量需要这些检查时,不需要更多的运行时间来执行任何内容保存(转换检查/垃圾回收等)。
答案 3 :(得分:4)
const是一个编译时常量 - 这意味着所有使用const变量的代码都被编译为包含const变量包含的常量表达式 - 发出的IL将包含该常量值本身。
这意味着您的方法的内存占用量较小,因为该常量不需要在运行时分配任何内存。
答案 4 :(得分:3)
除了小的性能改进之外,当您声明一个常量时,您明确地对自己和将使用您的代码的其他开发人员实施两个规则
代码中的所有关于可读性和通信的内容。
答案 5 :(得分:2)
const值也在对象的所有实例之间“共享”。它也可能导致内存使用率降低。
举个例子:
public class NonStatic
{
int one = 1;
int two = 2;
int three = 3;
int four = 4;
int five = 5;
int six = 6;
int seven = 7;
int eight = 8;
int nine = 9;
int ten = 10;
}
public class Static
{
static int one = 1;
static int two = 2;
static int three = 3;
static int four = 4;
static int five = 5;
static int six = 6;
static int seven = 7;
static int eight = 8;
static int nine = 9;
static int ten = 10;
}
.Net中的内存消耗很棘手,我不会假装理解它的细节,但是如果你实例化一个百万'静态'的列表,它可能会比你没有使用更少的内存。
static void Main(string[] args)
{
var maxSize = 1000000;
var items = new List<NonStatic>();
//var items = new List<Static>();
for (var i=0;i<maxSize;i++)
{
items.Add(new NonStatic());
//items.Add(new Static());
}
Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().WorkingSet64);
Console.Read();
}
使用'NonStatic'时,工作集为69,398,528,而使用静态时仅为32,423,936。
答案 6 :(得分:1)
const关键字告诉编译器它可以在编译时完全评估。有一个表演&amp;记忆优势,但它很小。
答案 7 :(得分:1)
C#中的常量提供命名的内存位置来存储数据值。这意味着变量的值将在编译时知道,并将存储在一个地方。
当您声明它时,它在Microsoft中间语言(MSIL)中是一种“硬编码”。
虽然有点,但它可以提高代码的性能。如果我声明一个变量,我可以使它成为一个常量,我总是这样做。不仅因为它可以提高性能,还因为它是常量的概念。否则,它们为什么存在?
反射器在这样的情况下非常有用。尝试声明变量然后使其成为常量,并查看 IL 中生成的代码。然后,您需要做的就是查看说明中的差异,并查看这些说明的含义。