我已经阅读了有关const
和static readonly
字段的信息。 我们有一些仅包含常量值的类。 用于我们系统中的各种事物。 所以我想知道我的观察是否正确:
这些常量值是否应该对所有公共内容始终保持static readonly
? 并且仅将const
用于内部/受保护/私有值吗?
您有什么推荐的吗? 我是否应该甚至不使用static readonly
字段,而应该使用属性?
#1楼
readonly
关键字与const
关键字不同。 const
字段只能在该字段的声明中初始化。 readonly
字段可以在声明中或在构造函数中初始化。 因此,取决于使用的构造函数, readonly
字段可以具有不同的值。 同样,虽然const
字段是编译时常量,但readonly
字段可用于运行时常量
#2楼
常量:常量就是“常量”,它的值是恒定的,但在编译时才是常量。 并且必须为其分配值。 默认情况下,const是静态的,我们无法在整个程序中更改const变量的值。
静态只读:静态只读类型变量的值可以在运行时分配,也可以在编译时分配,并在运行时更改。 但是只能在静态构造函数中更改此变量的值。 并且无法进一步更改。 在运行时只能更改一次
参考: c-sharpcorner
#3楼
这只是对其他答案的补充。 我不再重复(现在是四年后)。
在某些情况下, const
和非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
字段(或在可能的情况下,以其他方式更改)可以更改程序的行为。
#4楼
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的开发人员指定意图。 这样可以实现更好的版本控制行为以及更好的性能。
#5楼
const:
- 价值应在申报时给予
- 编译时间常数
只读:
- 可以在声明时或在运行时使用构造函数来提供该值。该值可能会因所使用的构造函数而异。
- 运行时间常数
#6楼
C#.Net中的const和静态只读字段之间有微小的区别
const必须在编译时用value初始化。
const在默认情况下是静态的,需要使用常量值进行初始化,以后将无法对其进行修改。 并非所有数据类型都可以使用它。 对于exDateTime。 不能与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则不可能。
#7楼
当向其他程序集显示在更高版本中可能会更改的值时,静态只读字段会很有用。
例如,假设程序集X
公开如下常量:
public const decimal ProgramVersion = 2.3;
如果程序集Y
引用X
并使用此常量,则编译时将值2.3烘焙到程序集Y
。 这意味着,如果稍后在常量设置为2.4的情况下重新编译X
,则Y
仍将使用旧值2.3,直到重新编译Y
静态只读字段可避免此问题。
另一种看待这种情况的方式是,将来可能发生变化的任何值在定义上都不是恒定的,因此不应将其表示为一个值。
#8楼
静态只读 :可以在运行时通过static
构造函数更改值。 但不是通过成员函数。
常量 :默认为static
。 不能在任何地方(Ctor,Function,运行时等,无处)更改值。
只读 :可以在运行时通过构造函数更改值。 但不是通过成员函数。
您可以看一下我的仓库: C#属性类型 。
#9楼
常量就像名称中所暗示的那样,字段不变,通常在代码编译时静态定义。
只读变量是可以在特定条件下更改的字段。
您可以在首次像常量一样声明它们时对其进行初始化,但通常它们是在构造函数内部的对象构造过程中进行初始化的。
在上述条件下,初始化后不能更改它们。
静态只读听起来对我来说是一个糟糕的选择,因为如果它是静态的并且永远不会更改,那么只需使用它的public const,如果可以更改则不是一个常量,然后根据您的需要,可以使用read -仅或仅是常规变量。
另外,另一个重要的区别是常量属于类,而只读变量属于实例!
#10楼
const :const变量值必须与声明一起定义,此后它将保持不变。 const是隐式静态的,因此无需创建类实例就可以访问它们。 这在编译时很有价值
ReadOnly :我们可以在声明时定义的只读变量值,以及在运行时使用构造函数。 只读变量不能在没有类实例的情况下访问。
静态只读 :我们可以在声明时定义静态静态变量值,并且只能通过静态构造函数来定义,而不能通过任何其他构造函数来定义。这些变量也可以在不创建类实例的情况下进行访问(作为静态变量)。
如果我们必须在不同的程序集中使用变量,则静态只读将是更好的选择。请在下面的链接中查看全部详细信息
https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/
#11楼
const(在编译时确定)可以在只读静态变量不能使用的情况下使用,例如switch语句或属性构造函数中。 这是因为只读字段仅在运行时解析,并且某些代码构造需要编译时保证。 可以在构造函数中计算只读静态变量,这通常是必不可少且有用的事情。 区别在于功能,我认为它们的用法也应如此。
就内存分配而言,至少对于字符串(作为引用类型)而言,似乎没有什么不同,因为两者都是内部的,并且将引用一个内部实例。
就我个人而言,我的默认值是静态只读,因为它对我来说更具语义和逻辑意义,尤其是因为在编译时不需要大多数值。 而且,顺便说一句,公开的只读静态数据在标记的回答状态中并不罕见或罕见:例如, System.String.Empty
是一个。
#12楼
public static readonly
字段有点不寻常; public static
属性(只有get
)会更常见(可能由private static readonly
字段支持)。
const
值直接刻录到调用站点中; 这是双刃的:
- 如果在运行时获取值(可能是从config中获取)是没有用的
- 如果更改const的值,则需要重建所有客户端
- 但它可以更快,因为它避免了方法调用...
- ... JIT有时可能内联了
如果该值永远不变,则const很好- Zero
等可以使const变得合理; p除此之外, static
属性更为常见。
#13楼
需要注意的一件事是const仅限于基本类型/值类型(字符串除外)
#14楼
很少有其他需要注意的事情:
const int a
- 必须初始化。
- 初始化必须在编译时进行 。
只读int
- 可以使用默认值,而无需初始化。
- 初始化可以在运行时完成(编辑:仅在构造函数内)。
#15楼
我的首选是在可能的情况下尽可能使用const ,如上所述,它仅限于文字表达式或不需要求值的内容。
如果我遇到了这个限制,那么我会退一步回到静态readonly ,但要注意一点。 正如Marc 在这里提到的,我通常会使用带有getter和后备私有static readonly字段的公共静态属性。
#16楼
如果使用者在不同的程序集中,我将使用static readonly
。 将const
和Consumer放在两个不同的程序集中是一个不错的选择 。