静态只读与常量

我已经阅读了有关conststatic readonly字段的信息。 我们有一些仅包含常量值的类。 用于我们系统中的各种事物。 所以我想知道我的观察是否正确:

这些常量值是否应该对所有公共内容始终保持static readonly ? 并且仅将const用于内部/受保护/私有值吗?

您有什么推荐的吗? 我是否应该甚至不使用static readonly字段,而应该使用属性?


#1楼

readonly关键字与const关键字不同。 const字段只能在该字段的声明中初始化。 readonly字段可以在声明中或在构造函数中初始化。 因此,取决于使用的构造函数, readonly字段可以具有不同的值。 同样,虽然const字段是编译时常量,但readonly字段可用于运行时常量

简短明了的MSDN参考资料在这里


#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有两个重载,一个重载为shortSystem.Int16 ),一个重载为objectSystem.Object )。 现在的问题是我的y参数是否适用于其中之一。

y是编译时常量(文字)(即const情况)时,重要的是,确实存在 int short的隐式转换前提是int是常量,并且C#编译器验证其值在short范围(即42 )。 请参见C#语言规范中的隐式常量表达式转换 。 因此,必须考虑两个过载。 首选重载Equals(short) (任何short是一个object ,但并非所有object都是short )。 因此y转换为short ,并且使用了重载。 然后, Equals比较两个相同值的short ,得到true

y不是常数时,不存在从intshort 隐式转换。 那是因为通常int可能太大而无法放入short 。 (确实存在显式转换,但我没有说Equals((short)y) ,所以没有关系。)我们看到只有一个重载适用,而Equals(object)适用。 所以y被装箱成object 。 然后, Equals将比较System.Int16System.Int32 ,并且由于运行时类型甚至不一致,因此将产生false

我们得出结论,在某些(罕见)情况下,将const类型成员更改为static readonly字段(或在可能的情况下,以其他方式更改)可以更改程序的行为。


#4楼

constreadonly是相似的,但是它们并不完全相同。

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:

  1. 价值应在申报时给予
  2. 编译时间常数

只读:

  1. 可以在声明时或在运行时使用构造函数来提供该值。该值可能会因所使用的构造函数而异。
  2. 运行时间常数

#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 。 将constConsumer放在两个不同的程序集中是一个不错的选择

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值