2016-08-09 1 views
5

私はbool.TrueStringの値を変更した場合、私はリフレクションを使用してそれを行うだろうとは:Reflectionを使用してType.Delimiterを変更できないのはなぜですか?

typeof(bool).GetField("TrueString", BindingFlags.Public | BindingFlags.Static).SetValue(null, "Yes"); 
Console.WriteLine(bool.TrueString); // Outputs "Yes" 

しかし、私はType.Delimiter、たとえば、の値を変更するために管理することはできません。

typeof(Type).GetField("Delimiter", BindingFlags.Public | BindingFlags.Static).SetValue(null, '-'); 
Console.WriteLine(Type.Delimiter); // Outputs "." 

なぜこれは?

+1

わからないようなDateTime Sまたは参照型のようなものは、とにかく恐ろしいアイデアだと思いintlong、およびcharのようなものが含まれていますが、ありません。 – itsme86

+0

ソースを見ると、2つのフィールドはほぼ同じであるが、それほど多くはないと宣言されています.1つは読み取り専用= "。"、もう1つは読み取り専用=別の読み取り専用リテラルです。 – pm100

+0

野生の推測。boolは 'struct'であり、' Type'は抽象クラスであるため、Reflectionはその構造体に黒い魔法を実行するかもしれません。私が言ったように、ちょうど推測 – lokusking

答えて

4

私はあなたがJITによって実行されています最適化に獲物を落下していると思います。実際にはそのフィールドの値を変更できますが、何らかの理由でその変更の結果がすぐには表示されません。

typeof(Type).GetField("Delimiter", BindingFlags.Public | BindingFlags.Static).SetValue(null, '-'); 
Func<char> getDelimiter =() => Type.Delimiter; 
Console.WriteLine(getDelimiter()); 

このコードは、フィールドの更新された値を確実に示してくれました。私はひどく驚いているとは言えません。フィールドは読み取り専用として宣言されるため、JITterはフィールドにアクセスするときにその前提を使用することがあります。あなたはいたずらと悪をやっている、本当にこれが正常な方法で動作することについての期待はないはずです。今

は、bool.TrueStringフィールドを変更する場合、これは現れなかった理由については、私の最高の推測では、Type.Delimiterが値型(char)であるのに対し、それは参照型(string)であることbool.TrueStringによるものだということです。私はこれが異なる最適化を誘発すると想像することができます。

私はこのコードを逆アセンブルを見ました:

 Console.WriteLine(bool.TrueString); 
006F2E53 8B 0D B8 10 40 03 mov   ecx,dword ptr ds:[34010B8h] 
006F2E59 E8 52 A6 77 54  call  54E6D4B0 

     Console.WriteLine(Type.Delimiter); 
006F2E5E B9 2E 00 00 00  mov   ecx,2Eh 
006F2E63 E8 B0 FA E0 54  call  55502918 

あなたはジッタがリテラル値'.'でそれを置き換えることにより、Type.Delimiterフィールドアクセスを離れて最適化されたことはかなりはっきりと見ることができます。 bool.TrueStringの静的フィールドアクセスは、実際のフィールドからまだロードされているようです。

+1

このコードを実行すると静的ctorが実行され、デリミタがx86コードに書き込まれるためです。デリゲートバージョンでは、このメソッドの区切り文字は参照されません。デリミタはx86コードに書き込まれますが、後で別の方法で書き込まれます。 – usr

+0

@usr LINQPadのコードをテストしてフィールドを変更しているのを実際に気付いたので、変更後にフィールド値を表示するように強制するデリゲートを作成するように促しました。正直言って、暗闇の中で私の側ではちょっとしたショットでしたが、それはうまくいきました。 – Kyle

1

差がbool.TrueStringが参照型であり、Type.Delimiterは値型であることです。これら二つの特性に対して同じコードを試してみてください、とあなたは同じ動作が表示されます:

public class A 
{ 
    public static readonly string S = "S"; 
    public static readonly char C = 'C'; 
} 

この問題が発生した理由は、あなたのメソッドが呼び出された最初の時間は、JITコンパイラの数字がstatic readonly値を焼くことができるかどうかということですアセンブリコードに定数として直接入力します。それができれば、そうです。

あなたが別のメソッドにフィールドにアクセスするコードを抽出する場合、その出力はその最初の実行は、フィールドの値が変更された後かあったかどうかに依存します。コードはすべて同じメソッドであるため、フィールドの値が変更される前に明確にJITされています。

あなたはCPUに面した命令にハードコード化することができる値型を使用している場合、このJITの最適化が適用されることがわかります。これは、文字列

関連する問題