静态只读与const – 不同的assemblyPOV?
关于这个问题有很多问题,但是没有(除了一个,但仍然是一个短的 )处理以下场景。
来自C#4书:
马克还写道:
如果更改const的值,则需要重建所有客户端
题 :
1)为什么? static readonly
和static
吗?
2)实际值保存在哪里 ?
3)如何使一个字段static readonly
实际上solve
“幕后”这个问题?
不,const是一个const,而不是一个静态 – 它是一个特殊情况,具有不同的规则; 它仅在编译时设置(不是运行时),并且处理方式不同
这里的关键是以下意思:
var foo = SomeType.StaticValue;
VS
var bar = SomeType.ConstValue;
在第一种情况下,它从SomeType
读取运行时的值,即通过ldsfld
; 但是,在第二种情况下,编译为值 ,即如果ConstValue
恰好是123
,则第二种情况与 :
var bar = 123;
在运行时,它来自SomeType
事实不存在 ,因为值( 123
) 由编译器评估并存储。 因此,它需要重建来获取新值。
更改为static readonly
意味着保留“从SomeType
加载值”。
以下是:
static int Foo() { return Test.Foo; } static int Bar() { return Test.Bar; } ... static class Test { public static readonly int Foo = 123; public const int Bar = 456; }
编译为:
.method private hidebysig static int32 Bar() cil managed { .maxstack 8 L_0000: ldc.i4 0x1c8 L_0005: ret } .method private hidebysig static int32 Foo() cil managed { .maxstack 8 L_0000: ldsfld int32 ConsoleApplication2.Test::Foo L_0005: ret }
请注意,在Bar
, ldc
直接加载一个值(0x1c8 == 456), Test
完全消失了。
为了完整性,const 是用静态字段实现的,但是 – 它是一个文字字段,意思是:在编译器中评估,而不是在运行时。
.field public static literal int32 Bar = int32(0x1c8) .field public static initonly int32 Foo
如果更改const的值,则需要重建所有客户端
这不是正确的解决方案。 如果更改const的值,那么它不是常量。 根据定义,常量永远不会改变它们的价值 。 你会改变 常 数值的想法意味着你在做一些逻辑上不可能的事情,所以事情当然会破裂; 你正在做一些你说你不会做的事情。 如果你四处寻找编译器,当你这样做时会受到伤害,那么就停止对编译器撒谎 。
黄金的价格不是一个常数。 您的银行名称不是常数。 程序的版本号不是常量。 这些东西会改变,所以不要让它们成为常量 。 常数是像pi这样的东西,或者是金primefaces中的质子数。
变量是可以变化的东西 – 这就是它们被称为“变量”的原因。 常数是保持不变的东西。 如果它可以变化,请将其变为变量。 如果它是常数,则使其成为常数。 它是如此简单。
这是为什么? static readonly和const都是静态的
当然。 这与它有什么关系? C#中的“static”表示“命名元素与类型相关联,而不是与该类型的任何特定实例相关联。” (“静态”因此是一个糟糕的术语选择; VB使用“共享”做得更好。)
名称是与类型还是实例相关联与名称是指常量还是变量的问题无关。
实际上值是在静态只读vsconst中保存的吗?
使用常量值时,无论在何处使用,该值都将“烘焙”。 这是安全的, 因为它永远不会改变 。 它永远不会改变, 因为它是不变的 ,这就是“常数”的含义。
使用变量时,每次都会在运行时查找变量的值。 “readonly”只表示“此变量只能在类构造函数或字段初始化程序中更改”。 它仍然是一个变量。 (*)
如何使一个字段静态只读 – 实际上解决了场景背后的这个问题?
你还没有说明问题所在,所以我不知道你要解决什么问题。
(*)只读字段被认为是构造函数之外的非常量值 ,因此不能改变可变值类型的只读字段,因此您不能将ref
作为只读字段然后改变引用。
1) const
在编译期间刚刚使用您提供的值解析。 static readonly
是一个静态变量。
2) static
值通常存储在堆上称为High Frequency Heap的特殊区域。 正如我之前所说,在编译时可以替换consts。
3)使其static readonly
将解决问题,因为您将在运行时读取变量值,而不是在编译时提供的值。
您已使用链接的图片回答了问题。 const
字段将被编译(“内联”)到程序集中 – 就像一个简单的搜索和替换。 static readonly
表示不允许更改的普通字段,仅在内存中存在一次,但仍由内存位置引用。
在.NET Framework中,常量不会分配内存区域,而是被视为值。 因此,您永远不能分配常量,但将常量加载到内存中会更有效,因为它可以直接注入到指令流中。 这消除了存储器之外的任何存储器访问,改善了参考的局部性。 http://www.dotnetperls.com/optimization
我想我们可以将常量视为代码中的硬编码值,但具有更好的维护和可用性。