静态只读与const - 不同的装配POV?

时间:2012-02-02 09:04:14

标签: c# static const readonly

关于这个主题有很多问题,但没有(one but still a short one除外)处理以下情况。

来自C#4书:

enter image description here

马克还写道:

  

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

问题:

1)为什么?是static readonly还是const - static

2)其中实际上是保存了值吗?

3)如何在场景后面“static readonly实际solve这个问题”?

5 个答案:

答案 0 :(得分:24)

  

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

这不是正确的解决方案。 如果更改const的值,那么它不是常量。常量是从不改变其值的东西。您更改常量的值的想法意味着您在逻辑上不可能做某事,因此当然事情会破裂;你正在做一些你说你不会做的事情。如果你四处寻找编译器,当你这样做时会受到伤害,那么就会停止对编译器说谎

黄金价格不是一个常数。您的银行名称不是常数。程序的版本号不是常量。这些事情会发生变化,因此不会使它们成为常量。常数就像pi,或者是原子中的质子数。

变量是可以变化的东西 - 这就是它们被称为“变量”的原因。常数是保持不变的东西。如果它可以变化,请将其变为变量。如果它是常数,则使其成为常数。就这么简单。

  

为什么? static readonly和const都是静态的

不确定。这与它有什么关系? C#中的“static”表示“命名元素与类型相关联,而不是与该类型的任何特定实例相关联。” (“静态”因此是一个糟糕的术语选择; VB使用“共享”做得更好。)

名称是否与类型或实例相关联与名称是否引用常量变量的问题无关。

  

实际上值是在静态只读vsconst中保存的吗?

使用常量值时,无论使用何处,都会被“烘焙”。这是安全的,因为它永远不会改变。它永远不会改变因为它是常数,而这就是“常数”的意思。

使用变量时,每次都会在运行时查找变量的值。 “readonly”只表示“此变量只能在类构造函数或字段初始化程序中更改”。它仍然是一个变量。 (*)

  

如何使字段静态只读 - 实际上解决了场景背后的这个问题?

你还没有说明问题是什么,所以我不知道你要解决什么问题。


(*)只读字段被认为是构造函数之外的非常量值,因此不能改变可变值类型的只读字段,因此您不能使用{{1转到readonly字段然后改变引用。

答案 1 :(得分:22)

不,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 ,但是 - 它是 literal 字段,意思是:在编译器处评估,而不是在运行时评估。

.field public static literal int32 Bar = int32(0x1c8)
.field public static initonly int32 Foo

答案 2 :(得分:6)

1)const在编译期间刚刚使用您提供的值解析。虽然static readonly是一个静态变量。

2)static值通常存储在名为High Frequency Heap的堆上的特殊区域中。正如我之前所说,在编译时替换了consts。

3)使它static readonly将解决问题,因为你将在运行时读取变量值,而不是在编译时提供的值。

答案 3 :(得分:4)

您已使用链接的图片回答了问题。 const字段将被编译(“内联”)到程序集中 - 就像一个简单的搜索和替换。 static readonly表示不允许更改的普通字段,仅在内存中存在一次,但仍由内存位置引用。

  

在.NET Framework中,常量未分配内存区域,但是   而是被视为价值观。因此,你永远不能分配一个   常量,但将常量加载到内存中更有效   因为它可以直接注入指令流。这个   消除了内存之外的任何内存访问,改进了   参考地点。 http://www.dotnetperls.com/optimization

答案 4 :(得分:0)

我想我们可以将常量视为代码中的硬编码值,但具有更好的维护和可用性产品。