我读过有关const
和static readonly
字段的内容。我们有一些只包含常量值的类。用于我们系统中的各种事物。所以我想知道我的观察是否正确:
对于所有公开的内容,这些常量值是否总是static readonly
?并且只对内部/受保护/私有值使用const
?
你推荐什么?我是否可能甚至不使用static readonly
字段,而是使用属性?
答案 0 :(得分:895)
public static readonly
字段有点不寻常; public static
属性(只有get
)会更常见(可能由private static readonly
字段支持)。
const
值直接刻录到呼叫站点;这是双刃:
如果值从不更改,那么const就可以了 - Zero
等进行合理的测试; p除此之外,static
属性更常见。
答案 1 :(得分:224)
如果 Consumer 位于不同的程序集中,我会使用static readonly
。将const
和消费者放在两个不同的程序集中是shoot yourself in the foot的好方法。
答案 2 :(得分:191)
const int a
readonly int a
答案 3 :(得分:162)
这只是对其他答案的补充。我不会重复它们(现在四年后)。
在某些情况下,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
({{1} })。现在的问题是一个或两个是否适用于我的System.Object
参数。
当y
是编译时常量(文字),y
情况时,确实存在来自 const
的隐式转换 to int
,前提是short
是一个常量,前提是C#编译器验证其值是否在int
范围内(short
1}}是。请参阅C#语言规范中的Implicit constant expression conversions。因此必须考虑两种重载。首选42
是首选(任何Equals(short)
都是short
,但并非所有object
都是object
)。因此short
转换为y
,并使用该重载。然后short
比较两个Equals
相同的值,并给出short
。
当true
不是常量时,不存在从y
到int
的隐式转换。这是因为一般来说short
可能太大而无法容纳int
。 (显式转换确实存在,但我没有说short
,因此不相关。)我们看到只有一个重载适用,{{1一个。因此,Equals((short)y)
被设置为Equals(object)
。然后y
会将object
与Equals
进行比较,由于运行时类型甚至不同意,因此会产生System.Int16
。
我们得出结论,在某些(罕见)情况下,将System.Int32
类型成员更改为false
字段(或者在可能的情况下,将其更改)可以更改程序的行为。< / p>
答案 4 :(得分:87)
需要注意的一点是 const 仅限于原始/值类型(例外是字符串)
答案 5 :(得分:24)
readonly
关键字与const
关键字不同。 const
字段只能在字段声明中初始化。可以在声明或构造函数中初始化readonly
字段。因此,readonly
字段可以具有不同的值,具体取决于所使用的构造函数。此外,虽然const
字段是编译时常量,但readonly
字段可用于运行时常量
答案 6 :(得分:21)
静态只读:
可以在运行时通过static
构造函数更改值。但不是通过成员函数。
常量:
默认情况下为static
。价值不能从任何地方改变(Ctor,Function,runtime等no-where)。
只读: 可以在运行时通过构造函数更改值。但不是通过成员函数。
您可以查看我的回购:C# property types。
答案 7 :(得分:15)
const
和readonly
相似,但它们并不完全相同。
const
字段是编译时常量,这意味着该值可以在编译时计算。 readonly
字段允许在构造类型期间必须运行某些代码的其他方案。构建完成后,无法更改readonly
字段。
例如,const
成员可用于定义以下成员:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
因为3.14和0之类的值是编译时常量。但是,请考虑您定义类型并希望提供一些预制实例的情况。例如,您可能希望定义一个Color类并为常用颜色(如Black,White等)提供“常量”。使用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的客户端使用它,也许通过交换黑白值。不用说,这会导致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);
}
现在,生成的代码能否依赖于A.C是编译时常量的事实?即,A.C的使用可以简单地用值0代替吗?如果对此说“是”,那么这意味着A的开发人员无法改变A.C初始化的方式 - 这将未经许可将A的开发人员联系起来。
如果您对此问题说“不”,则会错过重要的优化。也许A的作者肯定A.C永远是零。 const和readonly的使用允许A的开发者指定意图。这样可以获得更好的版本控制行为以及更好的性能。
答案 8 :(得分:12)
我的偏好是尽可能使用 const ,如上所述,仅限于文字表达或不需要评估的内容。
如果我遇到这种限制,那么我会回到静态只读,但有一点需要注意。我通常会使用带有getter和后备 private static readonly 字段的公共静态属性,因为Marc提及here。
答案 9 :(得分:7)
Const: Const只不过是“常量”,这是一个变量,其值在编译时是常量。并且必须为其分配值。默认情况下,const是静态的,我们不能在整个程序中更改const变量的值。
Static ReadOnly:静态只读类型变量的值可以在运行时分配,也可以在编译时分配,并在运行时更改。但是这个变量的值只能在静态构造函数中更改。而且无法进一步改变。它只能在运行时更改一次
答案 10 :(得分:6)
静态只读字段在暴露时是有利的 其他程序集中的值可能会在以后的版本中更改。
例如,假设程序集X
公开一个常量,如下所示:
public const decimal ProgramVersion = 2.3;
如果程序集Y
引用X
并使用此常量,则值为2.3
编译时将被装入程序集Y
。这意味着
如果稍后使用设置为2.4的常量重新编译X
,Y
仍然会
使用旧值2.3,直到重新编译Y
。静止的
readonly字段避免了这个问题。
另一种看待这种情况的方法是任何可能的价值 根据定义,未来的变化不是一成不变的,因此也应如此 不能代表一个。
答案 11 :(得分:3)
常量:
只读:
答案 12 :(得分:2)
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可以声明为static,但不是必需的。无需在声明时初始化。可以使用构造函数一次分配或更改其值。所以有可能一次改变readonly字段的值(无论如何,如果它是静态的),这对于const是不可能的。
答案 13 :(得分:1)
const :const变量值必须与声明一起定义,然后再声明 不会改变。 const是隐式静态的,因此无需创建类实例就可以访问它们。在编译时具有值
ReadOnly :我们可以在声明时定义的只读变量值,也可以在运行时使用构造函数。只读变量不能在没有类实例的情况下访问。
静态只读:我们可以在声明时定义静态静态变量值,并且只能通过静态构造函数来定义,而不能通过任何其他构造函数来定义。这些变量也可以在不创建类实例的情况下进行访问(作为静态变量)。
如果必须使用不同程序集中的变量,静态只读将是更好的选择。请检查下面链接中的完整详细信息
https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/
答案 14 :(得分:0)
常量就像名字所暗示的那样,字段不会改变,通常在编译时静态定义。
只读变量是在特定条件下可以更改的字段。
当您第一次将它们声明为常量时,它们可以初始化,但通常在构造函数内的对象构造期间初始化它们。
在初始化发生后,在上述条件下,它们无法更改。
静态只读对我来说是一个不好的选择,因为如果它是静态的并且永远不会改变,所以只要使用它就是公共const,如果它可以改变那么它不是一个常数然后,根据您的需要,您可以使用只读或只使用常规变量。
另外,另一个重要的区别是常量属于类,而只读变量属于实例!
答案 15 :(得分:0)
在switch语句或属性构造函数中不能使用只读静态变量的情况下,可以使用const(在编译时确定)。这是因为只读字段仅在运行时解析,并且某些代码构造需要编译时保证。可以在构造函数中计算只读静态变量,这通常是必不可少且有用的事情。差异是功能上的,我认为它们的用法也应如此。
就内存分配而言,至少对于字符串(作为引用类型)而言,似乎没有区别,因为两者都是被嵌入的,并且将引用一个被嵌入的实例。
就我个人而言,我的默认值是静态只读,因为它对我来说更具语义和逻辑意义,尤其是因为在编译时不需要大多数值。而且,顺便说一句,公开的只读静态数据在标记的回答状态中也并非罕见或罕见:例如,System.String.Empty
是一个。
答案 16 :(得分:0)
声明 const 和静态只读之间的另一个区别是内存分配。
静态字段属于对象的类型,而不是该类型的实例。结果,一旦第一次引用该类,静态字段将在其余时间“保留”在内存中,并且该类型的所有实例都将引用该静态字段的相同实例。>
另一方面, const 字段“属于该类型的实例。
如果释放内存对您来说更重要,则最好使用 const 。如果速度快,则使用静态只读。
答案 17 :(得分:0)
有一个重要的问题,上面的答案中没有提到,应该驱使您更喜欢“ const”,尤其是对于“ int”,“ string”等基本类型。
常量可以用作属性参数,不能使用静态只读字段!
Azure functions HttpTrigger, not using HttpMethods class in attribute
如果只有Microsoft将常量用于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!
答案 18 :(得分:0)
如果您可以提供编译时常量,请使用 const
:
private const int Total = 5;
如果您需要在运行时评估您的值,请使用 static readonly
:
private static readonly int GripKey = Animator.StringToHash("Grip");
这将导致编译错误,因为在编译时无法获取该值。
private const int GripKey = Animator.StringToHash("Grip");