声明字符串的公共静态只读变量 versus 公共常量 versus 公共静态常量

35
在每个项目中,我们都有一个用于存储该项目中使用的各种SQL语句的文件。对于类的声明方式以及字符串的声明方式,有几种不同的变体。
示例类声明:
internal sealed class ClassName
internal static class ClassName
public sealed class ClassName
public static class ClassName
internal class ClassName

示例字符串声明:

internal const string stringName
internal static string stringName
public static readonly string stringName
public static string stringName
public const string stringName

我不理解在不同声明之间的性能影响是什么。在这种情况/场景下是否有最佳做法?


关于这个问题,SO上已经有很多答案了...搜索C#中的static readonly const。 - Aaron McIver
1
我听说存储过程已经退出了舞台,但是这并不让我觉得这是一个合理的替代方案。 - Hans Passant
5个回答

86

我不理解在不同声明之间的性能影响是什么

评估数据库查询的成本可能是将从常量更改为只读字段或反之所需的成本差异的百万倍十亿倍。当你面对延迟以毫秒计算的数据库操作时,别担心那些只需要几纳秒的性能。

你应该关注的是语义,而不是性能。问题归结为“只读、常量或两者都不是?”

正确理解语义。“只读”字段意味着“每次执行此程序时,此字段只更改一次”,从null到其值。“const”字段表示“此值永远不会更改,不管是现在、下一个版本、还是永远,它是恒定不变的。”普通字段可以随时更改其值。

只读字段类似于版本号。它随时间变化,但在程序执行期间不变。常量类似于π或铅的原子序数;它是固定的、永恒的、永远不会改变的。对于在程序过程中发生变化的内容(如黄金价格),普通字段很合适。你的查询像哪种类型?它在此程序的整个过程中是恒定的、永久不变的,还是根本不是恒定的?


10
+1 表示“赞同”,意思是“你应该担心语义,而不是性能问题”。 - Dan Esparza
1
除了每个的语义含义之外,使用const而不是static readonly有什么特别的好处吗?我的理解是,static readonly可以做到const所能做到的甚至更多(例如动态初始化)。如果忽略语义,为什么会选择const而不是static readonly呢? - Nicholas Miller
@NickMiller:这是一个问答网站;这听起来像是一个相当好的问题候选人。如果您能举出一个具体的代码示例,那就更好了,这样可以更好地决定哪种方法更合适。 - Eric Lippert

9

根据使用字符串的代码,您应该选择一个访问修饰符(publicinternal)。

  • static const是编译器错误。

  • static readonly字段是一个普通字段,在静态构造函数之后无法设置。

  • const string将在编译时被其字面值替换。
    因此,它将提供稍微更好的性能(因为运行时不使用该字段)。
    但是,由于它在编译时被替换,对定义的任何更改都不会被其他程序集捕获,直到它们全部重新编译。

如果您的代码仅在一个程序集中使用,则可以使用const字符串。
但是,如果您的字符串由其他程序集使用(或可能在未来使用),则应使用static readonly字符串以实现可维护性。

还要注意,const字符串是一个编译时常量。
如果您需要在字符串中包含诸如机器名称或用户名之类的内容,则需要将其设置为static readonly


static const 为什么会导致编译错误的解释:Eric Lippert 的 不要重复自己 - Brian

7

关于const和static readonly的区别:

const在编译时是一个常量,因此性能更好。但另一方面,它在二进制版本控制方面存在问题。常量会被内联到使用它的程序集中,因此如果声明它的程序集发生更改,则其他程序集需要重新编译或者将使用过时的常量。

对于结构体,我通常使用静态属性而不是只读字段,因为Jitter可以优化它,但我仍然没有版本控制问题。


但是如果使用只读字段,JIT编译器可以更好地进行优化,因此在第一次进行优化时需要的优化量会更少。 - Tim Robinson
一个只读字段无法被优化,因为它是一个变量,而返回结构体的属性则可以在Jitter方面成为常量,因此可以进行优化。我在实现自己的定点类型时使用了这个技巧。 - CodesInChaos
@CodeInChaos:"常量会内联到使用它的程序集中..." 真的吗?对于值类型,我同意。但对于字符串肯定不是这样! - Jim Mischel
好的,可能是字符串没有内联。你测试过了吗?谷歌找到了这个:http://www.tek-tips.com/faqs.cfm?fid=6346 但当然它不是权威的。 - CodesInChaos
@CodeInChaos:我承认错误。你是正确的,而且我对编译器/运行时在这方面的行为感到非常惊讶。请参阅http://blog.mischel.com/2010/12/10/how-constant-is-a-constant/。 - Jim Mischel
感谢您的测试。我也不是100%确定。 - CodesInChaos

3

public static stringpublic const string在速度方面的差异微乎其微。

在IL中,这是两者之间的区别。

ldsfld someaddr.field 

并且

ldstr "your const here"

这里有答案。使用const时,每次使用它时,您实际上都在让汇编程序使用该文字,因此汇编程序将充斥着这些文字。而使用static,则会是“指向”中央位置的指针。
最大的问题在于:您无法对静态字符串执行switch case,但可以对const执行(应该如此)。
所以,我的建议是:如果需要使用switch-case,则必须使用const;如果不需要,则可能会选择static。
希望对您有所帮助。
尼古拉伊

0

鉴于您正在使用Visual Studio,使用public const而不是public static readonly的一个小好处是能够使用IntelliSense来“查看”const值。

e.g. Given:

public class Constants
{
     public const string ConstString = "Visible!";
     public static readonly string StaticReadonlyString = "Invisible!";
}

hovering over a string that's a constant hovering over a string variable that's static readonly


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