22

の値を変更するのString.Emptyは悪い考えであることは理解していますが、なぜそれができないのかわかりません。

私が言いたいことを理解するには、次のクラスを検討してください。

public class SomeContext 
{ 
    static SomeContext(){}
    public static readonly string Green = "Green";
    public static readonly SomeContext Instance = new SomeContext();

    private SomeContext(){}
    public readonly string Blue = "Blue";

    public static void PrintValues()
    { 
        Console.WriteLine(new { Green, Instance.Blue, String.Empty }.ToString());
    }
}

これら 3 つの読み取り専用フィールドを操作しようとする小さなコンソール アプリがあります。Blue と Green を Pink にすることはできますが、Empty は同じままです。

        SomeContext.PrintValues();
        ///  prints out : { Green = Green, Blue = Blue, Empty = }
        typeof(SomeContext).GetField("Blue").SetValue(SomeContext.Instance, "Pink");
        typeof(SomeContext).GetField("Green", BindingFlags.Public | BindingFlags.Static).SetValue(null, "Pink");
        typeof(String).GetField("Empty", BindingFlags.Public | BindingFlags.Static).SetValue(null, "Pink");
        SomeContext.PrintValues();
        ///  prints out : { Green = Pink, Blue = Pink, Empty = }

なんで?

String.Emptyもともと、定数ではない理由も尋ねました。別の投稿で質問のこの部分に対する回答を見つけ、質問のその部分を削除しました)。

注:「重複」のどれもこの問題に対する決定的な答えを持っていません。そのため、私はこの質問をしています。

4

1 に答える 1

16

マシンに .NET 4.5 があるため、変更できません。プロジェクトのフレームワーク ターゲット設定を 3.5 に変更するだけで、動作することがわかります。

CLR には、String.Empty の知識が組み込まれています。たとえば、Reflector または Reference Source を使用すると、System.String クラスがそれを初期化しないことがわかります。これは、CLR の起動時に行われます。4.5 がどのようにして変更が表示されないようにするのか、正確にはわかりません。実際にフィールドを変更しました。次のコード行を追加するだけです

  var s = typeof(String).GetField("Empty", 
             BindingFlags.Public | BindingFlags.Static).GetValue(null);
  Console.WriteLine(s);

そして、「ピンク」が表示されます。私の推測では、ジッターによって傍受されています。ただし、その確固たる証拠を示すことはできません。前例があります。たとえば、別の読み取り専用の静的値である Decimal.MaxValue をいじってみてください。ジッターはそれを認識し、フィールドを読み取らずに直接値を生成します。

まったく同じ件名の別の質問に賞金をかけていることがわかりました。280Z28の投稿もかなり似ています。

于 2013-11-13T22:46:03.483 に答える