[英]'Static readonly' vs. 'const'
我已经阅读了有关const
和static readonly
字段的信息。 我们有一些类只包含常量值。 它们用于我们系统中的各种事物。 所以我想知道我的观察是否正确:
对于所有公开的内容,这些常量值是否应该始终为static readonly
? 并且仅将const
用于internal
/ protected
/ private
值?
你有什么建议吗? 我是否应该甚至不使用static readonly
字段,而是使用属性?
public static readonly
字段有点不寻常; public static
属性(只有一个get
)会更常见(可能由private static readonly
字段支持)。
const
值直接烧入调用站点; 这是双刃剑:
如果值永远不会改变,那么 const 就可以了 - Zero
等构成合理的常量 ;p 除此之外, static
属性更常见。
如果消费者在不同的程序集中,我将使用static readonly
。 将const
和Consumer放在两个不同的程序集中是一种很好的打击自己的方式。
const int a
只读 int a
这只是对其他答案的补充。 我不会重复它们(现在四年后)。
在某些情况下, 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
的情况下,它有不从存在的隐式转换变得重要int
到short
规定, int
是一个常数,并且条件是C#编译器验证它的值是内short
的范围( 42
是)。 请参阅 C# 语言规范中的隐式常量表达式转换。 所以这两种重载都必须考虑。 重载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
字段(或其他方式,如果可能)可以更改程序的行为。
需要注意的一件事是const仅限于原始/值类型(字符串除外)。
静态只读:
可以在运行时通过static
构造函数更改该值。 但不是通过成员函数。
常数:
默认情况下是static
。 不能从任何地方(构造函数、函数、运行时等)更改值。
只读:
可以在运行时通过构造函数更改该值。 但不是通过成员函数。
您可以查看我的存储库: C# 属性类型。
readonly
关键字与const
关键字不同。 const
字段只能在字段声明时初始化。 readonly
字段可以在声明或构造函数中初始化。 因此, readonly
字段可以根据使用的构造函数具有不同的值。 此外,虽然const
字段是编译时常量,但readonly
字段可用于运行时常量
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 ,但有一个警告。 我通常会使用带有 getter 的公共静态属性和支持私有静态只读字段,正如 Marc 在此处提到的那样。
Const: Const 只不过是“常量”,一个变量,其值是常量,但在编译时。 并且必须为其分配一个值。 默认情况下,const 是静态的,我们不能在整个程序中更改 const 变量的值。
静态只读:静态只读类型变量的值可以在运行时分配或在编译时分配并在运行时更改。 但是这个变量的值只能在静态构造函数中改变。 并且无法进一步更改。 它只能在运行时更改一次
参考: c-sharpcorner
当向其他程序集公开可能在更高版本中更改的值时,静态只读字段是有利的。
例如,假设程序集X
公开一个常量,如下所示:
public const decimal ProgramVersion = 2.3;
如果程序集Y
引用X
并使用此常量,则值 2.3 将在编译时烘焙到程序集Y
。 这意味着如果X
稍后在常量设置为 2.4 的情况下重新编译,则Y
仍将使用旧值 2.3,直到重新编译Y
静态只读字段避免了这个问题。
另一种看待这个问题的方式是,任何可能在未来发生变化的值在定义上都不是恒定的,因此不应表示为一个。
Const :常量变量值必须与声明一起定义,之后它不会改变。 const 是隐式静态的,因此无需创建类实例我们就可以访问它们。 这在编译时有一个值。
ReadOnly :我们可以在声明以及在运行时使用构造函数时定义只读变量值。 没有类实例就不能访问只读变量。
静态只读:我们可以在声明时定义静态只读变量值,并且只能通过静态构造函数,但不能使用任何其他构造函数。 我们也可以在不创建类实例的情况下访问这些变量(作为静态变量)。
如果我们必须使用不同程序集中的变量,静态只读将是更好的选择。 请查看以下博客文章中的完整详细信息:
C#.Net 中的 const 和静态只读字段之间存在细微差别
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 可以声明为静态,但不是必需的。 无需在声明时初始化。 可以使用构造函数一次分配或更改其值。 所以有可能改变 readonly 字段的值一次(无关紧要,如果它是静态的),这是 const 不可能的。
常量:
只读:
const(在编译时确定)可用于只读静态不能的情况,例如在 switch 语句或属性构造函数中。 这是因为只读字段仅在运行时解析,并且某些代码构造需要编译时保证。 可以在构造函数中计算只读静态,这通常是必不可少且有用的东西。 区别是功能性的,在我看来它们的用法应该如此。
在内存分配方面,至少对于字符串(作为引用类型),两者似乎没有区别,因为两者都被实习并且将引用一个实习实例。
就我个人而言,我的默认值是只读静态的,因为它对我来说更具语义和逻辑意义,特别是因为在编译时不需要大多数值。 而且,顺便说一句,公共只读静态并不罕见或不常见,如标记答案所述:例如, System.String.Empty
就是其中之一。
声明const和static readonly 的另一个区别在于内存分配。
静态字段属于对象的类型而不是该类型的实例。 结果,一旦第一次引用该类,静态字段将在剩余时间内“存在”在内存中,并且该类型的所有实例都将引用静态字段的同一个实例。
另一方面, const字段“属于该类型的一个实例。
如果释放内存对您来说更重要,则更喜欢使用const 。 如果速度,则使用static readonly 。
常量就像名字暗示的那样,字段不会改变并且通常在编译时在代码中静态定义。
只读变量是可以在特定条件下更改的字段。
它们可以在您第一次像常量一样声明它们时被初始化,但通常它们是在构造函数内部的对象构造过程中初始化的。
在上述条件下,它们在初始化发生后不能更改。
静态只读对我来说听起来是一个糟糕的选择,因为如果它是静态的并且永远不会改变,那么只需使用 public const。 如果它可以改变,那么它就不是一个常量,然后,根据您的需要,您可以使用只读变量或仅使用常规变量。
另外,另一个重要的区别是常量属于类,而只读变量属于实例!
有一个重要的问题,在上面的答案中没有提到,应该促使您更喜欢“const”,尤其是对于“int”、“string”等基本类型。
常量可以作为属性参数,静态只读字段不行!
Azure 函数 HttpTrigger,未在属性中使用 HttpMethods 类
如果只有微软使用 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!
如果可以提供编译时常量,请使用const
:
private const int Total = 5;
如果您需要在运行时评估您的值,请使用static readonly
:
private static readonly int GripKey = Animator.StringToHash("Grip");
这将产生编译错误,因为在编译时无法获得该值。
private const int GripKey = Animator.StringToHash("Grip");
常量
静态只读
在重构期间,所有 const 都可以安全地转换为静态只读,但反之亦然,正如我们在上面看到的,当转换的代码可能会中断,因为可以在构造函数中初始化一些静态只读变量。
上面提到的另一个我不相信的区别是:
const
和static readonly
值不会在 Visual Studio IDE中应用 CodeLens。
static
仅获取属性 DO 将 CodeLens 应用于它们。
我认为添加 CodeLens 非常有价值。
注意:当前使用 Visual Studio 2022。
Const, readonly, static readonly - 执行类似操作但有重要区别的关键字:
• Const -是一个变量,其值为常量并在编译时分配。 您必须为其分配一个值。 默认常量是static,我们不能在整个程序中改变const变量的值。
• Readonly -表示我们可以在运行时更改的值,或者我们可以在运行时分配它,但只能通过非静态构造函数。
• Static 只读-值可以在运行时分配或在编译时分配并在运行时更改。 但是这个变量的值只能在 static 构造函数中改变。 并且无法进一步更改。 它只能在执行期间更改一次。
您可以在这里找到示例 - 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.