提问



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


对于所有公开的东西,这些常数值是否总是static readonly?并且只使用const作为内部/受保护/私有值?


你有什么建议?我是否可能甚至不使用static readonly字段,而是使用属性?

最佳参考


public static readonly字段有点不寻常; public static属性(只有get)会更常见(可能由private static readonly字段支持)。


const值直接烧到呼叫站点;这是双刃:



  • 如果在运行时获取值,则可能是无效的,可能来自config

  • 如果更改const的值,则需要重建所有客户端

  • 但它可以更快,因为它避免了方法调用......

  • ...无论如何有时候JIT都会内联



如果值从不改变,则const很好 - Zero等可以做出合理的反应; p除此之外,static属性更常见。

其它参考1


如果 Consumer 在不同的程序集中,我会使用static readonly。将const和消费者放在两个不同的组件中是一种很好的方式来拍摄自己的脚。[88]

其它参考2


其他一些事情


const int a



  • 必须初始化

  • 初始化必须在编译时



readonly int a



  • 可以使用默认值,而无需初始化

  • 初始化可以在运行时


其它参考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论证。[89]


y是编译时常量(文字),const的情况时,从 int 确实存在隐式转换变得很重要 short,只要int是常量,并且假设C#编译器验证其值在short的范围内(42是)。请参阅C#语言规范中的隐式常量表达式转换。因此必须考虑两种重载。过载Equals(short)是首选(任何shortobject,但并非所有object都是short。所以y转换为short,并使用该重载。然后Equals比较两个short的相同值,并给出true[90]


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


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

其它参考4


需要注意的一点是 const 仅限于原始/值类型(异常是字符串)

其它参考5


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


这里简短而明确的MSDN参考[91]

其它参考6


静态只读:
可以在运行时通过static构造函数更改值。但不是通过成员函数。


常量:
默认情况下static。价值不能从任何地方改变(Ctor,Function,runtime等no-where)。


只读:
可以在运行时通过构造函数更改值。但不是通过成员函数。


你可以看一下我的回购:C#属性类型。[92]

其它参考7


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


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


我的偏好是尽可能使用 const ,如上所述,它仅限于文字表达式或不需要评估的东西。


如果我遇到这个限制,那么我会回到静态只读,但有一点需要注意。我通常会使用带有getter和支持 private static readonly 字段的公共静态属性,正如Marc在这里提到的那样。

其它参考9


静态只读字段在暴露时是有利的
其他程序集中的值可能会在以后的版本中更改。


例如,假设程序集X公开一个常量,如下所示:


public const decimal ProgramVersion = 2.3;


如果汇编Y引用X并使用此常量,则值为2.3
将在编译时融入程序集Y。这意味着
如果X稍后用常量设置为2.4重新编译,Y仍然会
使用2.3的旧值,直到重新编译Y。静止的
readonly字段避免了这个问题。


另一种看待这种情况的方法是任何可能的价值
根据定义,未来的变化不是一成不变的,所以应该如此
不能代表一个人。

其它参考10



   Const: Const只不过是常量,这是一个变量,其值在编译时是常量。并且必须为它赋值。默认情况下,const是静态的,我们不能在整个程序中更改const变量的值。

  
   Static ReadOnly:静态只读类型变量的值可以在运行时分配,也可以在编译时分配,并在运行时更改。但是这个变量的值只能在静态构造函数中更改。而且无法进一步改变。它只能在运行时更改一次



参考:c-sharpcorner [94]

其它参考11


常量:



  1. 值应在声明时给出

  2. 编译时间常数



只读:



  1. 值可以在声明时或在运行时使用构造函数给出。值可能因使用的构造函数而异。

  2. 运行时间常数


其它参考12


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


常量就像名称所暗示的那样,字段不会改变,通常在编译时在代码中静态定义。


只读变量是在特定条件下可以更改的字段。


当你第一次将它们声明为常量时,它们可以被初始化,但通常它们在构造函数内的对象构造期间被初始化。


在初始化发生后,在上述条件下,它们无法更改。


静态只读声音对我来说是一个糟糕的选择,因为如果它是静态的并且它永远不会改变,那么只需使用它就是公共const,如果它可以改变那么它不是一个常数然后,根据你的需要,你既可以使用只读,也可以只使用常规变量。


另外,另一个重要的区别是常量属于类,而只读变量属于实例!