2016-08-09 13 views
5

अगर मैं bool.TrueString का मूल्य बदल रहे थे, मैं यह प्रतिबिंब का उपयोग कर चाहते हैं:मैं प्रतिबिंब का उपयोग कर 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

सुनिश्चित नहीं हैं कि शामिल है, एक भयानक विचार की तरह वैसे भी लगता है। – itsme86

+0

स्रोत को देखते हुए दो फ़ील्ड लगभग एक ही घोषित किए जाते हैं लेकिन काफी नहीं, केवल पढ़ने के लिए = "।" होता है, दूसरा केवल पढ़ने के लिए = एक और पढ़ने-केवल शाब्दिक होता है। – pm100

+0

एक जंगली अनुमान।चूंकि बूल एक 'संरचना' है और 'टाइप' एक सार वर्ग है, प्रतिबिंब उस संरचना पर कुछ काला जादू कर सकता है। जैसा कि मैंने कहा .. बस एक अनुमान – lokusking

उत्तर

4

मुझे लगता है कि आप जेआईटी द्वारा किए जा रहे अनुकूलन का शिकार हो रहे हैं। आप वास्तव में उस क्षेत्र के मूल्य को बदल सकते हैं, लेकिन, किसी कारण से, उस परिवर्तन के परिणाम तुरंत दिखाई नहीं देंगे।

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

इस कोड को मज़बूती से मेरे लिए मैदान के अद्यतन मूल्य से पता चला है: मैं कुछ बेवकूफ करके कि चारों ओर पाने में कामयाब रहे। मैं नहीं कह सकता कि मैं बहुत आश्चर्यचकित हूं; क्षेत्र को केवल पढ़ने के लिए घोषित किया गया है, इसलिए क्षेत्र तक पहुंचने पर जिटर उस धारणा का उपयोग कर सकता है। आप कुछ शरारती और बुरा कर रहे हैं, इस तरह से किसी भी तरह से काम करने के लिए वास्तव में कोई उम्मीद नहीं होनी चाहिए।

अब, क्यों यह दिखाई नहीं था, जब bool.TrueString क्षेत्र संशोधित करने के लिए के रूप में, मेरी सबसे अच्छी अनुमान है कि यह कारण bool.TrueString एक संदर्भ प्रकार (string) जबकि Type.Delimiter किया जा रहा है एक मान प्रकार (char) है। मैं कल्पना कर सकता हूं कि यह विभिन्न अनुकूलन को ट्रिगर कर रहा है।

 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 क्षेत्र का उपयोग देख सकते हैं:

मैं इस कोड के लिए disassembly पर देखने के लिए किया था। bool.TrueString के लिए स्थैतिक क्षेत्र का उपयोग अभी भी वास्तविक फ़ील्ड से लोड होने लगते हैं।

+1

ऐसा इसलिए है क्योंकि यह कोड स्थिर कोडर निष्पादित करता है, फिर Del86 को x86 कोड में जला देता है। प्रतिनिधि संस्करण इस विधि से डेलीमीटर का संदर्भ नहीं देता है। Delimiter अभी भी 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 मूल्य पके हुए किया जा सकता है एक स्थिर के रूप में सीधे असेंबली कोड में। अगर यह कर सकता है, तो यह करता है।

आप कोड है कि एक भिन्न तरीके से करने के लिए क्षेत्र तक पहुँचता बाहर निकालने हैं, तो इसके उत्पादन पर कि क्या अपने पहले रन या के बाद फ़ील्ड का मान बदल गया था इससे पहले कि था निर्भर करेगा। चूंकि आपका कोड सभी एक ही तरीके से है, तो फ़ील्ड के मान को बदलने से पहले यह स्पष्ट रूप से JITted था।

आप पाएंगे कि यदि आप एक मान प्रकार का उपयोग करते हैं जिसे सीपीयू-फेस निर्देशों में हार्ड-कोड किया जा सकता है, तो यह जेआईटी अनुकूलन लागू किया जाएगा। यह int, long, और char तरह बातें नहीं, बल्कि DateTime तरह बातें या तार की तरह संदर्भ प्रकार

संबंधित मुद्दे