简体   繁体   English

“静态只读”与“常量”

[英]'Static readonly' vs. 'const'

I've read around about const and static readonly fields.我已经阅读了有关conststatic readonly字段的信息。 We have some classes which contain only constant values.我们有一些类只包含常量值。 They are used for various things around in our system.它们用于我们系统中的各种事物。 So I am wondering if my observation is correct:所以我想知道我的观察是否正确:

Should these kind of constant values always be static readonly for everything that is public?对于所有公开的内容,这些常量值是否应该始终为static readonly And only use const for internal / protected / private values?并且仅将const用于internal / protected / private值?

What do you recommend?你有什么建议吗? Should I maybe even not use static readonly fields, but rather use properties maybe?我是否应该甚至不使用static readonly字段,而是使用属性?

public static readonly fields are a little unusual; public static readonly字段有点不寻常; public static properties (with only a get ) would be more common (perhaps backed by a private static readonly field). public static属性(只有一个get )会更常见(可能由private static readonly字段支持)。

const values are burned directly into the call-site; const值直接烧入调用站点; this is double edged:这是双刃剑:

  • it is useless if the value is fetched at runtime, perhaps from config如果该值是在运行时获取的,可能是从配置中获取的,则它是无用的
  • if you change the value of a const, you need to rebuild all the clients如果你改变了一个 const 的值,你需要重建所有的客户端
  • but it can be faster, as it avoids a method call...但它可以更快,因为它避免了方法调用......
  • ...which might sometimes have been inlined by the JIT anyway ...无论如何有时可能已被 JIT 内联

If the value will never change, then const is fine - Zero etc make reasonable consts ;p Other than that, static properties are more common.如果值永远不会改变,那么 const 就可以了 - Zero等构成合理的常量 ;p 除此之外, static属性更常见。

I would use static readonly if the Consumer is in a different assembly.如果消费者在不同的程序集中,我将使用static readonly Having the const and the Consumer in two different assemblies is a nice way to shoot yourself in the foot .constConsumer放在两个不同的程序集中是一种很好的打击自己的方式。

A few more relevant things to be noted:还有一些需要注意的相关事项:

const int a const int a

  • must be initialized.必须初始化。
  • initialization must be at compile time .初始化必须在编译时进行

readonly int a只读 int a

  • can use a default value, without initializing.可以使用默认值,无需初始化。
  • initialization can be done at run time (Edit: within constructor only).初始化可以在运行时完成(编辑:仅在构造函数中)。

This is just a supplement to the other answers.这只是对其他答案的补充。 I will not repeat them (now four years later).我不会重复它们(现在四年后)。

There are situations where a const and a non-const have different semantics.在某些情况下, const和非常量具有不同的语义。 For example:例如:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

prints out True , whereas:打印出True ,而:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

writes False .False

The reason is that the method x.Equals has two overloads, one that takes in a short ( System.Int16 ) and one that takes an object ( System.Object ).原因是方法x.Equals有两个重载,一个接受short ( System.Int16 ),另一个接受一个object ( System.Object )。 Now the question is whether one or both apply with my y argument.现在的问题是一个或两个是否适用于我的y论点。

When y is a compile-time constant (literal), the const case, it becomes important that there does exist an implicit conversion from int to short provided that the int is a constant, and provided that the C# compiler verifies that its value is within the range of a short (which 42 is).y是一个编译时间常数(字面),则const的情况下,它有不存在的隐式转换变得重要intshort规定, int是一个常数,并且条件是C#编译器验证它的值是内short的范围( 42是)。 See Implicit constant expression conversions in the C# Language Specification.请参阅 C# 语言规范中的隐式常量表达式转换 So both overloads have to be considered.所以这两种重载都必须考虑。 The overload Equals(short) is preferred (any short is an object , but not all object are short ).重载Equals(short)是首选(任何short都是object ,但并非所有object都是short )。 So y is converted to short , and that overload is used.所以y被转换为short ,并且使用了那个重载。 Then Equals compares two short of identical value, and that gives true .然后Equals比较两个short的相同值,并给出true

When y is not a constant, no implicit conversion from int to short exists.y不是常数时,不存在从intshort隐式转换。 That's because in general an int may be too huge to fit into a short .那是因为通常int可能太大而无法放入short (An explicit conversion does exist, but I didn't say Equals((short)y) , so that's not relevant.) We see that only one overload applies, the Equals(object) one. (确实存在显式转换,但我没有说Equals((short)y) ,所以这无关紧要。)我们看到只有一个重载适用,即Equals(object)一个。 So y is boxed to object .所以y被装箱到object Then Equals is going to compare a System.Int16 to a System.Int32 , and since the run-time types do not even agree, that will yield false .然后Equals会将System.Int16System.Int32进行比较,并且由于运行时类型甚至不一致,这将产生false

We conclude that in some (rare) cases, changing a const type member to a static readonly field (or the other way, when that is possible) can change the behavior of the program.我们得出结论,在某些(罕见)情况下,将const类型成员更改为static readonly字段(或其他方式,如果可能)可以更改程序的行为。

需要注意的一件事是const仅限于原始/值类型(字符串除外)。

Static Read Only :静态只读

The value can be changed through a static constructor at runtime.可以在运行时通过static构造函数更改该值。 But not through a member function.但不是通过成员函数。

Constant :常数

By default static .默认情况下是static A value cannot be changed from anywhere (constructor, function, runtime, etc. nowhere).不能从任何地方(构造函数、函数、运行时等)更改值。

Read Only :只读

The value can be changed through a constructor at runtime.可以在运行时通过构造函数更改该值。 But not through a member function.但不是通过成员函数。

You can have a look at my repository: C# property types .您可以查看我的存储库: C# 属性类型

The readonly keyword is different from the const keyword. readonly关键字与const关键字不同。 A const field can only be initialized at the declaration of the field. const字段只能在字段声明时初始化。 A readonly field can be initialized either at the declaration or in a constructor. readonly字段可以在声明或构造函数中初始化。 Therefore, readonly fields can have different values depending on the constructor used.因此, readonly字段可以根据使用的构造函数具有不同的值。 Also, while a const field is a compile-time constant, the readonly field can be used for runtime constants此外,虽然const字段是编译时常量,但readonly字段可用于运行时常量

Short and clear MSDN reference here 简短明了的 MSDN 参考在这里

const and readonly are similar, but they are not exactly the same. constreadonly很相似,但它们并不完全相同。

A const field is a compile-time constant, meaning that that value can be computed at compile-time. const字段是编译时常量,这意味着可以在编译时计算该值。 A readonly field enables additional scenarios in which some code must be run during construction of the type. readonly字段支持在类型的构造期间必须运行某些代码的其他场景。 After construction, a readonly field cannot be changed.构建后, readonly字段不能更改。

For instance, const members can be used to define members like:例如, const成员可用于定义如下成员:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

Since values like 3.14 and 0 are compile-time constants.因为像 3.14 和 0 这样的值是编译时常量。 However, consider the case where you define a type and want to provide some pre-fab instances of it.但是,请考虑您定义类型并希望提供它的一些预制实例的情况。 Eg, you might want to define a Color class and provide "constants" for common colors like Black, White, etc. It isn't possible to do this with const members, as the right hand sides are not compile-time constants.例如,您可能想要定义一个 Color 类并为常见颜色(如黑色、白色等)提供“常量”。使用 const 成员是不可能做到这一点的,因为右侧不是编译时常量。 One could do this with regular static members:可以使用常规静态成员来做到这一点:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

But then there is nothing to keep a client of Color from mucking with it, perhaps by swapping the Black and White values.但是没有什么可以阻止 Color 的客户端使用它,也许是通过交换 Black 和 White 值。 Needless to say, this would cause consternation for other clients of the Color class.不用说,这会引起 Color 类的其他客户的惊愕。 The "readonly" feature addresses this scenario. “只读”功能解决了这种情况。

By simply introducing the readonly keyword in the declarations, we preserve the flexible initialization while preventing client code from mucking around.通过在声明中简单地引入readonly关键字,我们保留了灵活的初始化,同时防止客户端代码乱七八糟。

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

It is interesting to note that const members are always static, whereas a readonly member can be either static or not, just like a regular field.有趣的是,const 成员总是静态的,而 readonly 成员可以是静态的,也可以不是,就像常规字段一样。

It is possible to use a single keyword for these two purposes, but this leads to either versioning problems or performance problems.可以将单个关键字用于这两个目的,但这会导致版本问题或性能问题。 Assume for a moment that we used a single keyword for this (const) and a developer wrote:假设我们为此(const)使用了一个关键字,并且开发人员写道:

public class A
{
    public static const C = 0;
}

and a different developer wrote code that relied on A:另一个开发人员编写了依赖于 A 的代码:

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

Now, can the code that is generated rely on the fact that AC is a compile-time constant?现在,生成的代码能否依赖于 AC 是编译时常量这一事实? Ie, can the use of AC simply be replaced by the value 0?即,AC 的使用可以简单地替换为值 0 吗? If you say "yes" to this, then that means that the developer of A cannot change the way that AC is initialized -- this ties the hands of the developer of A without permission.如果你对此说“是”,那么这意味着 A 的开发者不能改变 AC 的初始化方式——这在未经许可的情况下束缚了 A 的开发者的手。

If you say "no" to this question then an important optimization is missed.如果你对这个问题说“不”,那么就错过了一个重要的优化。 Perhaps the author of A is positive that AC will always be zero.也许 A 的作者肯定 AC 永远为零。 The use of both const and readonly allows the developer of A to specify the intent. const 和 readonly 的使用允许 A 的开发人员指定意图。 This makes for better versioning behavior and also better performance.这有助于实现更好的版本控制行为和更好的性能。

My preference is to use const whenever I can, which, as mentioned in previous answers, is limited to literal expressions or something that does not require evaluation.我的偏好是尽可能使用const ,正如前面的答案中提到的,它仅限于文字表达式或不需要评估的东西。

If I hit up against that limitation, then I fallback to static readonly , with one caveat.如果我遇到了这个限制,那么我会退回到static readonly ,但有一个警告。 I would generally use a public static property with a getter and a backing private static readonly field as Marc mentions here .我通常会使用带有 getter 的公共静态属性和支持私有静态只读字段,正如 Marc 在此处提到的那样。

Const: Const is nothing but "constant", a variable of which the value is constant but at compile time. Const: Const 只不过是“常量”,一个变量,其值是常量,但在编译时。 And it's mandatory to assign a value to it.并且必须为其分配一个值。 By default a const is static and we cannot change the value of a const variable throughout the entire program.默认情况下,const 是静态的,我们不能在整个程序中更改 const 变量的值。

Static ReadOnly: A Static Readonly type variable's value can be assigned at runtime or assigned at compile time and changed at runtime.静态只读:静态只读类型变量的值可以在运行时分配或在编译时分配并在运行时更改。 But this variable's value can only be changed in the static constructor.但是这个变量的值只能在静态构造函数中改变。 And cannot be changed further.并且无法进一步更改。 It can change only once at runtime它只能在运行时更改一次

Reference: c-sharpcorner参考: c-sharpcorner

A static readonly field is advantageous when exposing to other assemblies a value that might change in a later version.当向其他程序集公开可能在更高版本中更改的值时,静态只读字段是有利的。

For instance, suppose assembly X exposes a constant as follows:例如,假设程序集X公开一个常量,如下所示:

public const decimal ProgramVersion = 2.3;

If assembly Y references X and uses this constant, the value 2.3 will be baked into assembly Y when compiled.如果程序集Y引用X并使用此常量,则值 2.3 将在编译时烘焙到程序集Y This means that if X is later recompiled with the constant set to 2.4, Y will still use the old value of 2.3 until Y is recompiled.这意味着如果X稍后在常量设置为 2.4 的情况下重新编译,则Y仍将使用旧值 2.3,直到重新编译Y A static readonly field avoids this problem.静态只读字段避免了这个问题。

Another way of looking at this is that any value that might change in the future is not constant by definition, and so should not be represented as one.另一种看待这个问题的方式是,任何可能在未来发生变化的值在定义上都不是恒定的,因此不应表示为一个。

Const : Constant variable values have to be defined along with the declaration and after that it won't change. Const :常量变量值必须与声明一起定义,之后它不会改变。 const are implicitly static, so without creating a class instance we can access them. const 是隐式静态的,因此无需创建类实例我们就可以访问它们。 This has a value at compile time.这在编译时有一个值。

ReadOnly : We can define read-only variable values while declaring as well as using the constructor at runtime. ReadOnly :我们可以在声明以及在运行时使用构造函数时定义只读变量值。 Read-only variables can't access without a class instance.没有类实例就不能访问只读变量。

Static readonly : We can define static readonly variable values while declaring as well as only through a static constructor, but not with any other constructor.静态只读:我们可以在声明时定义静态只读变量值,并且只能通过静态构造函数,但不能使用任何其他构造函数。 We can also access these variables without creating a class instance (as static variables).我们也可以在不创建类实例的情况下访问这些变量(作为静态变量)。

Static readonly will be better choice if we have to consume the variables in different assemblies.如果我们必须使用不同程序集中的变量,静态只读将是更好的选择。 Please check the full details in the below blog post:请查看以下博客文章中的完整详细信息:

Const Strings – a very convenient way to shoot yourself in the foot Const Strings – 一种非常方便的用脚射击自己的方法

There is a minor difference between const and static readonly fields in C#.Net C#.Net 中的 const 和静态只读字段之间存在细微差别

const must be initialized with value at compile time. const 必须在编译时用值初始化。

const is by default static and needs to be initialized with constant value, which can not be modified later on. const 默认是静态的,需要用常量值初始化,以后不能修改。 It can not be used with all datatypes.它不能与所有数据类型一起使用。 For ex- DateTime.对于前日期时间。 It can not be used with DateTime datatype.它不能与 DateTime 数据类型一起使用。

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

readonly can be declared as static, but not necessary. readonly 可以声明为静态,但不是必需的。 No need to initialize at the time of declaration.无需在声明时初始化。 Its value can be assigned or changed using constructor once.可以使用构造函数一次分配或更改其值。 So there is a possibility to change value of readonly field once (does not matter, if it is static or not), which is not possible with const.所以有可能改变 readonly 字段的值一次(无关紧要,如果它是静态的),这是 const 不可能的。

const:常量:

  1. value should be given upon declaration值应在声明时给出
  2. compile time constant编译时间常数

readonly:只读:

  1. value can be given upon declaration or during runtime using constructors.The value may vary depend upon the constructor used.值可以在声明时或在运行时使用构造函数给出。该值可能因所使用的构造函数而异。
  2. run time constant运行时间常数

A const (being determined at compile-time) can be used in cases where a readonly static can't, like in switch statements, or attribute constructors. const(在编译时确定)可用于只读静态不能的情况,例如在 switch 语句或属性构造函数中。 This is because readonly fields are only resolved at run-time, and some code constructs require compile time assurance.这是因为只读字段仅在运行时解析,并且某些代码构造需要编译时保证。 A readonly static can be calculated in a constructor, which is often an essential and useful thing.可以在构造函数中计算只读静态,这通常是必不可少且有用的东西。 The difference is functional, as should be their usage in my opinion.区别是功能性的,在我看来它们的用法应该如此。

In terms of memory allocation, at least with strings (being a reference type), there seems to be no difference in that both are interned and will reference the one interned instance.在内存分配方面,至少对于字符串(作为引用类型),两者似乎没有区别,因为两者都被实习并且将引用一个实习实例。

Personally, my default is readonly static, as it makes more semantic and logical sense to me, especially since most values are not needed at compile time.就我个人而言,我的默认值是只读静态的,因为它对我来说更具语义和逻辑意义,特别是因为在编译时不需要大多数值。 And, by the way, public readonly statics are not unusual or uncommon at all as the marked answer states: for instance, System.String.Empty is one.而且,顺便说一句,公共只读静态并不罕见或不常见,如标记答案所述:例如, System.String.Empty就是其中之一。

Another difference between declaring const and static readonly is in memory allocation.声明conststatic readonly 的另一个区别在于内存分配。

A static field belongs to the type of an object rather than to an instance of that type.静态字段属于对象的类型而不是该类型的实例。 As a result, once the class is referenced for the first time, the static field would "live" in the memory for the rest of time, and the same instance of the static field would be referenced by all instances of the type.结果,一旦第一次引用该类,静态字段将在剩余时间内“存在”在内存中,并且该类型的所有实例都将引用静态字段的同一个实例。

On the other hand, a const field "belongs to an instance of the type.另一方面, const字段“属于该类型的一个实例。

If memory of deallocation is more important for you, prefer to use const .如果释放内存对您来说更重要,则更喜欢使用const If speed, then use static readonly .如果速度,则使用static readonly

Constants are like the name implies, fields which don't change and are usually defined statically at compile time in the code.常量就像名字暗示的那样,字段不会改变并且通常在编译时在代码中静态定义。

Read-only variables are fields that can change under specific conditions.只读变量是可以在特定条件下更改的字段。

They can be either initialized when you first declare them like a constant, but usually they are initialized during object construction inside the constructor.它们可以在您第一次像常量一样声明它们时被初始化,但通常它们是在构造函数内部的对象构造过程中初始化的。

They cannot be changed after the initialization takes place, in the conditions mentioned above.在上述条件下,它们在初始化发生后不能更改。

Static read-only sounds like a poor choice to me since, if it's static and it never changes, so just use it public const.静态只读对我来说听起来是一个糟糕的选择,因为如果它是静态的并且永远不会改变,那么只需使用 public const。 If it can change then it's not a constant and then, depending on your needs, you can either use read-only or just a regular variable.如果它可以改变,那么它就不是一个常量,然后,根据您的需要,您可以使用只读变量或仅使用常规变量。

Also, another important distinction is that a constant belongs to the class, while the read-only variable belongs to the instance!另外,另一个重要的区别是常量属于类,而只读变量属于实例!

There is one important question, that is not mentioned anywhere in the above answers, and should drive you to prefer "const" especially for basic types like "int", "string" etc.有一个重要的问题,在上面的答案中没有提到,应该促使您更喜欢“const”,尤其是对于“int”、“string”等基本类型。

Constants can be used as Attribute parameters , static readonly field not!常量可以作为属性参数,静态只读字段不行!

Azure functions HttpTrigger, not using HttpMethods class in attribute Azure 函数 HttpTrigger,未在属性中使用 HttpMethods 类

If only microsoft used constants for Http's GET, POST, DELETE etc.如果只有微软使用 Http 的 GET、POST、DELETE 等常量。

It would be possible to write应该可以写

[HttpTrigger(AuthorizationLeve.Anonymous,  HttpMethods.Get)] // COMPILE ERROR: static readonly, 

But instead I have to resort to但我不得不求助于

[HttpTrigger(AuthorizationLeve.Anonymous,  "GET")] // STRING

Or use my own constant:或者使用我自己的常量:

public class HttpConstants
{
    public const string Get = "GET";
}

[HttpTrigger(AuthorizationLeve.Anonymous,  HttpConstants.Get)] // Compile FINE!

Use const if you can provide a compile-time constant:如果可以提供编译时常量,请使用const

private const int Total = 5;

Use static readonly if you need your value evaluated during run-time:如果您需要在运行时评估您的值,请使用static readonly

private static readonly int GripKey = Animator.StringToHash("Grip");

This will give a compile error because it is impossible to get the value at compile-time.这将产生编译错误,因为在编译时无法获得该值。

private const int GripKey = Animator.StringToHash("Grip");

Const常量

  1. Can be applied only for fields.只能应用于字段。 Value should be in code compile time.值应该在代码编译时。
  2. Suited for removing magic "strings","int/double", (primitive types) etc across the code which is known already before compiling the code.适合在编译代码之前在代码中删除魔术“字符串”、“int/double”、(原始类型)等。
  3. After compiling the value will be placed all over the compiled code wherever constant is used.编译后,该值将放置在使用常量的所有编译代码中。 So if you have a huge string used many places, then watch out before making it const.所以如果你有一个巨大的字符串在很多地方使用,那么在使它成为 const 之前要小心。 consider using static read only.考虑使用静态只读。

Static read only静态只读

  1. Static read only be applied for fields/props and static can be used for methods.静态只读适用于字段/道具,静态可用于方法。 (on side note)When static is applied to methods, the complied code does not pass the 'this' parameter to the method and hence you cannot access the instance data of the object. (附注)当静态应用于方法时,编译后的代码不会将“this”参数传递给方法,因此您无法访问对象的实例数据。
  2. Suitable for values which may change after compiling the code.适用于编译代码后可能更改的值。 Like values initialized from configuration, during startup of application etc.像从配置中初始化的值,在应用程序启动期间等。
  3. After compiling the code, the ref to value is used in IL code and may be slower compared to using const, but compiled code is small编译代码后,在 IL 代码中使用 ref to value 可能比使用 const 慢,但编译后的代码很小

During Refactoring, All const can be safely converted to Static read only, but not vise versa as we have seen above when converted code may break as some static readonly variable could be initialized in constructors.在重构期间,所有 const 都可以安全地转换为静态只读,但反之亦然,正如我们在上面看到的,当转换的代码可能会中断,因为可以在构造函数中初始化一些静态只读变量。

One additional difference that I don't believe is mentioned above:上面提到的另一个我不相信的区别是:

const and static readonly values don't get CodeLens applied to them in the Visual Studio IDE. conststatic readonly值不会在 Visual Studio IDE中应用 CodeLens。

static get only properties DO get CodeLens applied to them. static仅获取属性 DO 将 CodeLens 应用于它们。

代码镜头示例

I consider the addition of CodeLens to be quite valuable.我认为添加 CodeLens 非常有价值。

Note: Currently using Visual Studio 2022.注意:当前使用 Visual Studio 2022。

Const, readonly, static readonly - keywords that perform a similar action but have an important difference: Const, readonly, static readonly - 执行类似操作但有重要区别的关键字:

Const - is a variable whose value is constant and is assigned at compile time. Const -是一个变量,其值为常量并在编译时分配。 You must assign a value to it.您必须为其分配一个值。 The default constants are static, and we cannot change the value of the const variable throughout the program.默认常量是static,我们不能在整个程序中改变const变量的值。

Readonly - means a value that we can change at run time, or we can assign it at run time, but only through a non-static constructor. Readonly -表示我们可以在运行时更改的值,或者我们可以在运行时分配它,但只能通过非静态构造函数。

Static readonly - values can be assigned at run time or assigned at compile time and changed at run time. Static 只读-值可以在运行时分配或在编译时分配并在运行时更改。 But the value of this variable can be changed only in the static constructor.但是这个变量的值只能在 static 构造函数中改变。 And cannot be changed further.并且无法进一步更改。 It can only be changed once during execution.它只能在执行期间更改一次。

Examples you can find here - https://www.c-sharpcorner.com/UploadFile/c210df/difference-between-const-readonly-and-static-readonly-in-C-Sharp/您可以在这里找到示例 - https://www.c-sharpcorner.com/UploadFile/c210df/difference-between-const-readonly-and-static-readonly-in-C-Sharp/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM