2016-08-09 16 views
5

Ben bool.TrueString değerini değiştirmek için olsaydı, ben Yansıma kullanarak yapardım: AncakNeden Reflection kullanarak Type.Delimiter değiştiremiyorum?

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

, ben diyelim ki, değerini değiştirmek için yönetemez, Type.Delimiter:

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

Neden bu?

+1

Değil emin dizeleri gibi int, long ve char gibi şeyler değil, işler DateTime gibi s veya referans türlerini içerir yine korkunç bir fikir gibi görünüyor. – itsme86

+0

kaynağa bakarak iki alan hemen hemen aynı ancak tam olarak bildirilmez, biri salt okunur = ".", Diğeri salt okunur = başka bir salt okunur değişmez. – pm100

+0

Vahşi bir tahmin.Bool bir 'struct' ve 'Type' soyut bir sınıf olduğu için, Reflection bu yapı üzerinde biraz kara büyü yapabilir. Dediğim gibi .. sadece bir tahmin – lokusking

cevap

4

JIT tarafından gerçekleştirilmekte olan bir optimizasyon için ava düştüğünüzü düşünüyorum. Aslında bu alanın değerini değiştirebilirsin, ancak bir nedenden ötürü, bu değişikliğin sonuçları hemen görünmeyecek.

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

Bu kod güvenilir benim için alanın güncellenmiş değeri gösterdi: Ben aptal şey yaparak o çevrede başardı. Çok şaşırdığımı söyleyemem; alan salt okunur olarak bildirilir, bu nedenle JITter, alana erişirken bu varsayımı kullanabilir. Yaramaz ve kötülükle ilgili bir şey yapıyorsunuz, bunun aklı başında çalışmak için hiçbir beklentisi olmamalı.

Şimdi bool.TrueString alanını değiştirirken bu kadar yoktu neden gelince, benim en iyi tahminim bir değer tipi (char) nedeniyle bool.TrueStringType.Delimiter oysa bir referans tipi (string) ediliyor olmasıdır. Bu tetikleyici farklı optimizasyonları hayal edebiliyorum.

 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 

Oldukça net bir şekilde jitter edebi değeri '.' ile değiştirerek Type.Delimiter alan erişimini uzakta optimize görebiliriz:

ben bu kodu sökme bakmak yaptı. bool.TrueString için statik alan erişimi hala gerçek alandan yükleniyor gibi görünüyor.

+1

Çünkü bu kodun çalınması statik ctor'u çalıştırır, sonra Delimiter'i x86 koduna yazar. Temsilci sürümü, bu yöntemden Delimiter başvurmuyor. Ayırıcı hala x86 koduna ancak daha sonra farklı bir yöntemle yazılır. – usr

+0

@usr LINQPad'deki kodu sınayarak alanın değiştiğini fark ettim, bu da beni değiştirdikten sonra alan değerini görmek için jiti zorlamak için bir temsilci oluşturmayı denememi sağladı. Dürüst olmak gerekirse, karanlıkta bir parça atıştı, ama sanırım işe yaradı. – Kyle

1

Fark, bool.TrueString bir referans türüdür ve Type.Delimiter bir değer türüdür. bu iki özellik karşı aynı kodu deneyin ve aynı davranışı görürsünüz:

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

Böyle nedeni, yöntemi denir ilk kez JIT derleyicisi rakamlar static readonly değeri pişmiş edilip edilemeyeceğini olmasıdır montaj kodunu doğrudan sabit olarak. Eğer yapabilirse, öyle. Eğer farklı bir yönteme alanını erişen kodunu ayıklamak, sonra çıkış, ilk çalıştırma veya alanın değeri değiştirildi sonra önce olup olmadığı bağlıdır

. Kodunuz hep aynı yöntemde olduğu için, alanın değeri değiştirilmeden önce açıkça JITted oldu.

İşlemciye bakan yönergelere kodlanmış bir değer türü kullanırsanız, bu JIT optimizasyonu uygulanacaktır. Bu,

İlgili konular