我已经阅读了有关 const
和 static readonly
字段的信息。我们有一些只包含常量值的类。它们用于我们系统中的各种事物。所以我想知道我的观察是否正确:
对于所有公开的内容,这些常量值是否应该始终为 static readonly
?并且仅将 const
用于内部/受保护/私有值?
你有什么建议吗?我是否应该甚至不使用 static readonly
字段,而是使用属性?
static readonly
的一个非常有趣的单一案例:try using a const inside an IEnumerator
which would trigger an unrecheable yield
and you'll get a dreaded "Internal compiler error"。我没有在 Unity3D 之外测试代码,但我相信这是 mono 或 .NET bug。尽管如此,这是一个 c# 问题。
static readonly
不能在 switch-case
语句中用作 case
变量,为此需要 const
。
static readonly
也不能用作属性参数
public static readonly
字段有点不寻常; public static
属性(只有 get
)会更常见(可能由 private static readonly
字段支持)。
const
值直接写入调用站点;这是双刃剑:
如果值是在运行时获取的,可能是从配置中获取的,它是无用的
如果更改 const 的值,则需要重建所有客户端
但它可以更快,因为它避免了方法调用......
...无论如何有时可能已被 JIT 内联
如果值将从不改变,那么 const 就可以了 - Zero
等构成合理的 consts ;p 除此之外,static
属性更常见。
如果 Consumer 在不同的程序集中,我会使用 static readonly
。将 const
和 Consumer 放在两个不同的程序集中是 shoot yourself in the foot 的好方法。
internal const
或 public static readonly
取决于所需的可见性。
public const
有有效的用途(例如,标准的任何部分。任何时候我使用 XML , 有一个包含一堆 public const string
的命名空间文件。)但通常,只有在正确考虑其含义后才能使用 public const
。
还有一些相关的事情需要注意:
const int a
必须初始化。
初始化必须在编译时进行。
只读 int a
可以使用默认值,无需初始化。
初始化可以在运行时完成(编辑:仅在构造函数中)。
ctor
内。
这只是对其他答案的补充。我不会重复它们(现在是四年后)。
在某些情况下,const
和非常量具有不同的语义。例如:
const int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
打印出 True
,而:
static readonly int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
写入 False
。
原因是方法 x.Equals
有两个重载,一个接受 short
(System.Int16
),另一个接受 object
(System.Object
)。现在的问题是一个或两个是否适用于我的 y
论点。
当 y
是编译时常量(字面量)时,在 const
的情况下,确实存在隐式转换 from int
to { 变得很重要5} 前提是 int
是一个常量,并且 C# 编译器验证其值是否在 short
的范围内(42
是)。请参阅 C# 语言规范中的 Implicit constant expression conversions。因此,必须考虑这两个重载。重载 Equals(short)
是首选(任何 short
都是 object
,但并非所有 object
都是 short
)。因此 y
被转换为 short
,并使用了该重载。然后 Equals
比较两个相同值的 short
,得到 true
。
当 y
不是常量时,不存在从 int
到 short
的隐式转换。这是因为通常 int
可能太大而无法放入 short
。 (确实存在 显式 转换,但我没有说 Equals((short)y)
,所以这不相关。)我们看到只有一个重载适用,即 Equals(object)
一个。所以 y
被装箱到 object
。然后 Equals
会将 System.Int16
与 System.Int32
进行比较,由于运行时类型甚至不一致,这将产生 false
。
我们得出结论,在某些(极少数)情况下,将 const
类型成员更改为 static readonly
字段(或其他方式,如果可能的话)可以改变程序的行为。
short x = 42;
合法。因为那里有一个 int
,即文字 42
,它隐式地变成了 short x
。但是,他们可能已将其限制为数字文字;但是,他们也选择允许 short x = y;
之类的东西,其中 y
被定义为 const int y = 42;
,然后他们就这样结束了。
需要注意的一件事是 const 仅限于原始/值类型(字符串除外)。
const
也可以用于其他类型,只是它必须初始化为 null,这使它无用:)
System.Exception
中的异常? :)
const
的唯一值类型是 sbyte
、byte
、short
、ushort
、int
、uint
、 long
、ulong
、char
、float
、double
、decimal
、bool
以及任何 enum
类型。 const
不能用于其他值类型,例如 DateTime
或 TimeSpan
或 BigInteger
。它也不能用于 IntPtr
结构(被某些人认为是“原始”类型;术语原始类型在 C# 中令人困惑)。 ↵↵ const
可用于所有引用类型。如果类型为 string
,则可以指定任何字符串值。否则,该值必须为 null
。
default
制作 任何东西(值和引用类型)const
。对于 struct
类型,它是一个所有成员都设置为默认值的实例。
静态只读:
可以在运行时通过 static
构造函数更改该值。但不是通过成员函数。
持续的:
默认情况下 static
。无法从任何地方(构造函数、函数、运行时等)更改值。
只读:
该值可以在运行时通过构造函数进行更改。但不是通过成员函数。
您可以查看我的存储库:C# property types。
readonly
关键字不同于 const
关键字。 const
字段只能在字段声明时初始化。 readonly
字段可以在声明或构造函数中初始化。因此,readonly
字段可以具有不同的值,具体取决于所使用的构造函数。此外,虽然 const
字段是编译时常量,但 readonly
字段可用于运行时常量
Short and clear MSDN reference here
const
和 readonly
相似,但并不完全相同。
const
字段是编译时常量,这意味着可以在编译时计算该值。 readonly
字段支持在构造类型期间必须运行某些代码的其他场景。构造后,不能更改 readonly
字段。
例如,const
成员可用于定义成员,例如:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
因为像 3.14 和 0 这样的值是编译时常量。但是,请考虑您定义类型并希望提供一些预制实例的情况。例如,您可能想要定义一个 Color 类并为黑色、白色等常见颜色提供“常量”。使用 const 成员是不可能的,因为右侧不是编译时常量。可以使用常规静态成员执行此操作:
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);
}
但是,没有什么可以阻止 Color 的客户使用它,也许是通过交换 Black 和 White 值。不用说,这会引起 Color 类的其他客户的恐慌。 “只读”功能解决了这种情况。
通过在声明中简单地引入 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);
}
有趣的是,const 成员始终是静态的,而 readonly 成员可以是静态的,也可以不是静态的,就像常规字段一样。
可以为这两个目的使用单个关键字,但这会导致版本控制问题或性能问题。假设我们为此使用了一个关键字(const)并且开发人员写道:
public class A
{
public static const C = 0;
}
另一个开发人员编写了依赖于 A 的代码:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
现在,生成的代码可以依赖于 AC 是编译时常量这一事实吗?即,AC 的使用可以简单地用值 0 代替吗?如果您对此说“是”,那么这意味着 A 的开发人员无法更改 AC 的初始化方式——这在未经许可的情况下束缚了 A 的开发人员的手。
如果你对这个问题说“不”,那么就会错过一个重要的优化。也许 A 的作者肯定 AC 将永远为零。 const 和 readonly 的使用允许 A 的开发人员指定意图。这有助于更好的版本控制行为和更好的性能。
我的偏好是尽可能使用 const ,如前面的答案所述,它仅限于文字表达式或不需要评估的东西。
如果我遇到了这个限制,那么我会回退到 static readonly,但要注意一点。正如 Marc 提到的 here,我通常会使用带有 getter 和支持 private static readonly 字段的公共静态属性。
常量:常量变量值必须与声明一起定义,之后它不会改变。常量是隐式静态的,所以我们可以在不创建类实例的情况下访问它们。这在编译时有一个值。
ReadOnly:我们可以在声明时定义只读变量值,也可以在运行时使用构造函数。没有类实例,只读变量无法访问。
静态只读:我们可以在声明时以及仅通过静态构造函数定义静态只读变量值,但不能使用任何其他构造函数。我们也可以在不创建类实例(作为静态变量)的情况下访问这些变量。
如果我们必须在不同的程序集中使用变量,静态只读将是更好的选择。请查看以下博客文章中的完整详细信息:
Const Strings – a very convenient way to shoot yourself in the foot
当向其他程序集公开可能在更高版本中更改的值时,静态只读字段是有利的。
例如,假设程序集 X
公开一个常量,如下所示:
public const decimal ProgramVersion = 2.3;
如果程序集 Y
引用 X
并使用此常量,则值 2.3 将在编译时烘焙到程序集 Y
中。这意味着,如果稍后重新编译 X
并将常量设置为 2.4,则在重新编译 Y
之前,Y
仍将使用旧值 2.3。静态只读字段避免了这个问题。
另一种看待这一点的方式是,任何可能在未来发生变化的值在定义上都不是恒定的,因此不应表示为一个。
Const:Const 只不过是“常量”,它是一个变量,其值是常量,但在编译时。并且必须为其分配一个值。默认情况下,const 是静态的,我们不能在整个程序中更改 const 变量的值。静态只读:静态只读类型变量的值可以在运行时赋值或在编译时赋值并在运行时更改。但是这个变量的值只能在静态构造函数中改变。并且无法进一步更改。它只能在运行时更改一次
C#.Net 中的 const 和 static 只读字段之间存在细微差别
const 必须在编译时用值初始化。
const 默认是静态的,需要用常量值初始化,以后不能修改。它不能用于所有数据类型。对于前日期时间。它不能与 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 可以声明为静态的,但不是必需的。声明时无需初始化。可以使用构造函数一次分配或更改其值。所以有可能改变一次只读字段的值(没关系,如果它是静态的),这对于 const 是不可能的。
常量:
值应在声明编译时间常数时给出
只读:
可以在声明时或在运行时使用构造函数给出值。值可能因使用的构造函数而异。运行时间常数
const(在编译时确定)可以用于只读静态不能使用的情况,例如 switch 语句或属性构造函数。这是因为只读字段仅在运行时解析,并且某些代码构造需要编译时保证。可以在构造函数中计算只读静态,这通常是必不可少且有用的东西。区别是功能性的,我认为它们的用法也应该如此。
在内存分配方面,至少对于字符串(作为引用类型)而言,似乎没有区别,因为两者都是实习生并且将引用一个实习生实例。
就个人而言,我的默认值是只读静态的,因为它对我来说更具语义和逻辑意义,特别是因为在编译时不需要大多数值。而且,顺便说一下,公共只读静态数据并不罕见或不常见,正如标记的答案所述:例如,System.String.Empty
是一。
声明 const 和 static readonly 的另一个区别在于内存分配。
静态字段属于对象的类型,而不属于该类型的实例。结果,一旦第一次引用该类,静态字段将在内存中“存在”剩余时间,并且该静态字段的同一实例将被该类型的所有实例引用。
另一方面,一个 const 字段“属于该类型的一个实例。
如果释放内存对您来说更重要,则更喜欢使用 const。如果速度快,则使用静态只读。
如果您可以提供编译时常量,请使用 const
:
private const int Total = 5;
如果您需要在运行时评估您的值,请使用 static readonly
:
private static readonly int GripKey = Animator.StringToHash("Grip");
这将产生编译错误,因为在编译时无法获取该值。
private const int GripKey = Animator.StringToHash("Grip");
常量就像名字所暗示的那样,不会改变的字段,通常在编译时在代码中静态定义。
只读变量是可以在特定条件下更改的字段。
它们可以在你第一次像常量一样声明它们时被初始化,但通常它们在构造函数内的对象构造期间被初始化。
在上述条件下,它们在初始化发生后无法更改。
对我来说,静态只读听起来像是一个糟糕的选择,因为如果它是静态的并且永远不会改变,那么只需使用它 public const。如果它可以更改,那么它不是一个常量,然后,根据您的需要,您可以使用只读变量或仅使用常规变量。
另外,另一个重要的区别是常量属于类,而只读变量属于实例!
有一个重要的问题,在上述答案的任何地方都没有提到,应该驱使你更喜欢“const”,特别是对于“int”、“string”等基本类型。
常量可以作为属性参数,静态只读字段不行!
Azure functions HttpTrigger, not using HttpMethods class in attribute
如果只有微软为 Http 的 GET、POST、DELETE 等使用常量。
可以写
[HttpTrigger(AuthorizationLeve.Anonymous, HttpMethods.Get)] // COMPILE ERROR: static readonly,
但相反,我不得不求助于
[HttpTrigger(AuthorizationLeve.Anonymous, "GET")] // STRING
或者使用我自己的常量:
public class HttpConstants
{
public const string Get = "GET";
}
[HttpTrigger(AuthorizationLeve.Anonymous, HttpConstants.Get)] // Compile FINE!
"GET"
,因为它要短得多,而且无论如何都不会改变。 🤷♂️
常量
只能应用于字段。值应该在代码编译时。适合在编译代码之前在代码中删除魔术“字符串”、“int/double”、(原始类型)等。编译后,该值将放置在使用常量的所有编译代码中。所以如果你有一个巨大的字符串在很多地方使用,那么在使它成为 const 之前要小心。考虑使用静态只读。
静态只读
静态只读适用于字段/道具,静态可用于方法。 (附注)当静态应用于方法时,编译后的代码不会将“this”参数传递给方法,因此您无法访问对象的实例数据。适用于编译代码后可能更改的值。就像从配置中初始化的值,在应用程序启动期间等。编译代码后,对值的引用在 IL 代码中使用,与使用 const 相比可能会更慢,但编译后的代码很小
在重构期间,所有 const 都可以安全地转换为静态只读,但反之亦然,正如我们在上面看到的,当转换的代码可能会中断,因为可以在构造函数中初始化一些静态只读变量。
上面提到了我不相信的另一个区别:
const
和 static readonly
值不会在 Visual Studio IDE 中应用 CodeLens。
static
仅获取属性确实会将 CodeLens 应用于它们。
https://i.stack.imgur.com/9fVpP.png
我认为添加 CodeLens 非常有价值。
注意:当前使用 Visual Studio 2022。
const、readonly、static readonly - 执行类似操作但有重要区别的关键字:
• Const - 是一个变量,其值为常量,在编译时分配。您必须为其分配一个值。默认常量是静态的,我们不能在整个程序中改变 const 变量的值。
• Readonly - 表示我们可以在运行时更改的值,或者我们可以在运行时分配它,但只能通过非静态构造函数。
• 静态只读- 值可以在运行时分配或在编译时分配并在运行时更改。但是这个变量的值只能在静态构造函数中改变。并且无法进一步更改。在执行过程中只能更改一次。
您可以在此处找到示例 - https://www.c-sharpcorner.com/UploadFile/c210df/difference-between-const-readonly-and-static-readonly-in-C-Sharp/
readonly
字段不能在 switch/case 语句中使用,而您需要它们是const
。