2012-02-02 7 views
16

この件に関する多くの質問がありますが、(one but still a short oneを除く)誰も次のシナリオを処理していません。スタティック読み取り専用と定数 - 異なるアセンブリのPOV?

C#4本から:

enter image description here

マークにも書きました:

をあなたはCONSTの値を変更した場合、あなたはすべての クライアント

を再構築する必要があります

質問:

1)なぜですか? static readonlyconst - staticの両方ですか?

2)実際に値は保存されますか?

3)どのように「シーンの後ろに」solve実際にこの問題をフィールドstatic readonlyを作っていますか?

+2

これは、別のアセンブリからの変数を参照する代わりに、コンパイラが定数の値を "インライン"にするためです。 – ken2k

+2

アセンブリ間のconstのこの動作を知りませんでした。 良い質問 –

答えて

21

いいえ、constはconstであり、静的ではありません。これは特殊なケースで、異なるルールを使用します。それはコンパイル時(実行時ではない)でのみセットであり、それは異なる方法で処理され

ここに核心が何であるかを以下の手段:

var foo = SomeType.StaticValue; 

var bar = SomeType.ConstValue; 

最初のの場合、実行時に値 SomeTypeから、つまり ldsfldを介して値を読み取ります。しかし、第2のケースでは、の値に がコンパイルされます。

var bar = 123; 

実行時に、それはSomeTypeから来ているという事実は、値(123)として、存在しないことによってを評価した。ConstValue123であることを起こる場合には、第二のにが同一ありますコンパイラ、および保存されます。したがって、新しい値を取得するには再構築が必要です。

static readonlyに変更すると、「SomeTypeからの値のロード」が保持されます。

だから次Barに、ldcが完全Testで、直接(0x1c8 == 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 
} 

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; 
} 

はとしてコンパイル行った。完全のために

、constのは、静的フィールドで実装されているが、 - それはつまり、リテラルフィールドです:コンパイラではなく、実行時に評価。

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

優秀な回答ありがとうございますが、constは暗黙的に静的ではありませんか? –

+1

@Royiよく、*はい*それはILで '.field ... static'と実装され、C#では' TypeName.ConstName'としてアクセスされます - しかし重要なことは**意味です**;セマンティクスの意味では、通常の静的メンバー(フィールド/小道具)へのアクセスとconstメンバーへのアクセスには大きな違いがあります。 –

4

あなたはリンク先の画像であなたの質問に既に回答しています。 constフィールドは、単純な検索や置換のように、アセンブリにコンパイル(インライン展開)されます。 static readonlyは、変更が許可されておらず、メモリ内に1回だけ存在する通常のフィールドを意味しますが、まだメモリロケーションによって参照されます。

.NET Frameworkでは、定数にはメモリ領域が割り当てられていませんが、代わりに が値と見なされます。したがって、 を決して代入することはできませんが、定数をメモリにロードする方が効率的です。 これは命令ストリームに直接注入できるためです。この は、メモリの外部へのメモリアクセスを排除し、 参照の局所性を改善します。 http://www.dotnetperls.com/optimization

6

1)constはちょうどあなたが提供した値を持つコンパイル時に解決されます。 static readonlyは静的変数です。

2)static値は通常、ヒープ上の特別な領域に格納されます(High Frequency Heap)。前に述べたように、constはコンパイル時に代入されます。

3)それをstatic readonlyにすると、コンパイル時に提供される値ではなく、実行時に変数値を読み込むため、この問題が解決されます。

24

あなたがconstの値を変更した場合、あなたは正しい解決策ではありませんすべてのクライアント

を再構築する必要があります。 constの値を変更した場合、定数ではありませんでした。定数は定義によるものです値を決して変更しないもの。あなたがの値をの定数をに変更するということは、論理的に不可能な何かをしていることを意味します。あなたがしないと言ったことをやっている。あなたがコンパイラに横たわっていて、それをするときに痛いなら、はコンパイラに横たわっていません。

金の価格は一定ではありません。あなたの銀行の名前は定数ではありません。あなたのプログラムのバージョン番号は定数ではありません。これらは変化するので、は定数にしません。定数は、piのようなもの、または金の原子中のプロトンの数です。

変数はに変わるものです。そのため、変数は「変数」と呼ばれています。定数は一定のものです...定数です。それが変わる場合は、それを変数にします。定数の場合は定数にします。それはそれと同じくらい簡単です。

なぜですか?静的読み取りと静的読み取りの両方が静的です。

確かです。それはそれと何が関係していますか? C#の "静的"は、 "指定された要素が型の特定のインスタンスではなく型に関連付けられていることを意味します。"

名前が型またはインスタンスに関連付けられているかどうかは、その名前がを参照しているかどうかの問題とは関係ありません(静的な用語は用語の貧しい選択です。定数または変数

実際に値は両方とも静的読み取り専用vsconstに保存されていますか?

あなたが一定の値を使用する場合、それが使用されている場所、は「焼き」されます。それは決してを変更するつもりはないので、安全なです。それは定数であるので決してを変更するつもりはなく、それは "定数"の意味です。

変数を使用すると、毎回実行時に変数の値が参照されます。 "readonly"は "この変数はクラスコンストラクタまたはフィールド初期化子でのみ変更できます"という意味です。それはまだ変数です。 (*)

フィールドを静的に読み取り専用にする方法 - 実際にこの問題をシーンの後ろで解決する方法はありますか?

あなたは問題が何であるかを明記していないので、解決しようとしている問題はわかりません。変更可能な値型の読み取り専用フィールドが変異することができないように、そしてあなたが読み取り専用にrefを取ることができないように(*)読み取り専用フィールドは、コンストラクタ外非定数値であると考えられて


フィールドに入力し、参照を変更します。

+1

今、私はこの文章が意味することを理解しています!:あなたがコンパイラに嘘をついているなら、それは復讐を得るでしょう--Henry Spencer – kokabi

+0

あなたの文章はとても良いです。なぜC#についての素晴らしい本を書いてみませんか?それは私の夢です! – kokabi

+1

@ programmer1:ありがとう!私はEssential C#の最後のカップルエディションを書いてMarkを助けましたが、ほとんどの文章は彼のものです。私は自分のC#の本を書くことを考えましたが、それはたくさんの仕事です。また、私はC#のデザインについてのブログを書いています。 –

0

コードでは、定数をハードコードされた値と考えることができますが、メンテナンスと使いやすさの点では優れています。

関連する問題