静态只读与常量
我读过关于const
和static readonly
字段。 我们有一些只包含常数值的类。 用于我们系统中的各种事物。 所以我想知道我的观察是否正确:
这些常量值是否应该static readonly
为公有的? 而只使用const
的内部/保护/私人价值?
你有什么build议? 我应该甚至可能不使用static readonly
字段,而是使用属性也许?
公共静态只读字段有点不寻常; 公共静态属性(只有一个get
)会更常见(也许由一个私有静态只读字段支持)。
Const值直接烧入呼叫站点; 这是双刃的:
- 如果在运行时(也许是从configuration中获取)取值,这是毫无用处的
- 如果你改变一个const的值,你需要重build所有的客户端
- 但它可以更快,因为它避免了方法调用…
- 无论如何,它可能有时被JIT内联
如果该值永远不会改变,那么const是好的 – Zero
等等做出合理的常量; -p除此之外,静态属性更常见。
如果消费者在不同的程序集中,我将使用static readonly
。 在两个不同的程序集中, const
和消费者是一个很好的方式来打自己的脚 。
其他一些事情
const int a
- 必须初始化
- 初始化必须在编译时
只读int a
- 可以使用默认值,而不需要初始化
- 初始化可以在运行时
这只是对其他答案的补充。 我不会重复(现在四年后)。
在某些情况下, const
和non-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
是一个编译时常量(literal), const
情况下,重要的是确实存在从 int
到 short
一个隐式转换,前提是int
是一个常量,并且假定C#编译器validation它的值在一个short
的范围(这是42
)。 请参阅C#语言规范中的隐式常量expression式转换 。 所以这两个重载都必须考虑。 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
,并且由于运行时types甚至不同意,这将产生false
。
我们得出这样的结论:在一些(罕见)的情况下,将一个const
types的成员改为一个static readonly
字段(或者static readonly
,如果可能的话)可以改变程序的行为。
有一点需要注意的是, const被限制在基本types/值types(exception是string)
readonly
关键字与const
关键字不同。 const
字段只能在该字段的声明处初始化。 readonly
字段可以在声明中或在构造函数中初始化。 因此, readonly
字段可以具有不同的值,具体取决于所使用的构造函数。 另外,虽然const
字段是编译时常量,但readonly
字段可用于运行时常量
简短并清除MSDN参考
Const和readonly是相似的,但它们并不完全一样。 const字段是一个编译时常量,意味着这个值可以在编译时计算出来。 只读字段使得在构buildtypes期间必须运行一些代码的附加场景成为可能。 施工结束后,只能读取字段不能更改。
例如,const成员可以用来定义成员,如:
struct Test { public const double Pi = 3.14; public const int Zero = 0; }
因为像3.14和0这样的值是编译时常量。 但是,请考虑您定义types并希望提供一些预制实例的情况。 例如,你可能想要定义一个Color类,并为黑色,白色等常见的颜色提供“常量”。这是不可能的,因为右边不是编译时常量。 可以用普通的静态成员来做到这一点:
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 = r; green = g; blue = b; } }
但是没有任何东西可以让Color的一个客户免受黑客的攻击,也许通过交换黑白价值。 不用说,这会导致Color类的其他客户感到惊愕。 “只读”function解决了这种情况。 通过简单地在声明中引入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 = r; green = g; blue = b; } }
有趣的是,const成员总是静态的,而只读成员可以是静态的,也可以不是静态的,就像普通的成员一样。
为了这两个目的,可以使用单个关键字,但这会导致版本问题或性能问题。 假设我们使用了一个关键字(const),一个开发者写道:
public class A { public static const C = 0; }
而不同的开发者写的代码依赖于A:
public class B { static void Main() { Console.WriteLine(AC); } }
现在,生成的代码是否可以依赖于AC是编译时常量? 也就是说,交stream电的使用可以简单地用0代替吗? 如果你对此表示“是”,那么这意味着A的开发者不能改变AC被初始化的方式 – 这在未经许可的情况下将A的开发者的手联系起来。 如果你对这个问题说“不”,那么错过了一个重要的优化。 也许A的作者肯定AC会始终为零。 同时使用const和readonly允许A的开发人员指定意图。 这使得更好的版本行为和更好的性能。
我的首选是使用常量,只要我可以,如上所述仅限于文字expression式或不需要评估的东西。
如果我忍受了这个限制,那么我只能回避静态 ,只有一个警告。 我将通常使用一个公共静态属性与一个getter和一个支持私人静态只读字段,马克在这里提到。
静态只读 :可以在运行时通过静态构造函数更改值。 但不是通过成员函数
常量 :默认静态。 值不能从任何地方改变(Ctor,Function,运行时间等)
只读 :可以在运行时通过构造函数更改值。 但不是通过成员函数
你可以看看我的回购: C#属性types
静态只读字段在向其他程序集公开可能会在更高版本中更改的值时是有利的。
例如,假设程序集X
暴露一个常量,如下所示:
public const decimal ProgramVersion = 2.3;
如果程序集Y
引用了X
并且使用了这个常量,那么在编译时,值2.3将被编译到程序集Y
。 这意味着如果X
稍后被重新编译为常量设置为2.4,则Y
将仍然使用旧值2.3直到Y
被重新编译。 静态只读字段避免了这个问题。
另一种看待这个问题的方式是,将来任何可能改变的价值都不是一成不变的,所以不应该表示为一个。
Const: Const只不过是“常量”,其值是恒定的,但是在编译时。 而且必须为它分配一个值。 默认情况下,const是静态的,我们不能在整个程序中改变constvariables的值。
静态只读:静态只读typesvariables的值可以在运行时分配,也可以在编译时分配,并在运行时更改。 但是这个variables的值只能在静态构造函数中改变。 而且不能进一步改变。 它只能在运行时更改一次
参考: c-sharpcorner
常量:
- 应在申报时给予价值
- 编译时间常量
只读:
- 值可以在声明时或运行时使用构造函数给出。值可能会根据所使用的构造函数而有所不同。
- 运行时间常数
C#.Net中的const和静态只读字段之间有一个小小的区别
const在编译时必须用值初始化。
const默认是静态的,需要用常量初始化,以后不能修改。 它不能与所有的数据types一起使用。 对于以前的DateTime。 它不能与DateTime数据types一起使用。
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
只读可以声明为静态,但不是必需的。 申报时无需进行初始化。 它的值可以使用构造函数分配或更改一次。 所以有可能改变只读字段的值一次(不重要,如果它是静态的),这是不可能与const。
常量就像名字所暗示的那样,字段不会改变,通常在编译时静态地定义在代码中。
只读variables是在特定条件下可以更改的字段。
当你第一次将它们声明为一个常量时,它们可以被初始化,但是通常它们在构造函数中的对象构造期间被初始化。
在初始化发生后,在上述条件下不能更改它们。
静态只读对我来说是一个糟糕的select,因为如果它是静态的,它永远不会改变,所以只需使用它的公共常量,如果它可以改变,那么它不是一个常量,然后,根据您的需要,您可以使用读只是或者只是一个常规variables。
此外,另一个重要的区别是一个常量属于类,而只读variables属于实例!