2010-11-10 17 views
8

एक नवीनता के रूप में, मैं यह देखने की कोशिश कर रहा हूं कि वीएस कंपाइलर द्वारा उत्पन्न रनटाइम दिखने वाले कोड पर जेनरेट किए गए हल्के वजन कोड से आईएल कितना अलग है, जैसा कि मैंने देखा है कि वीएस कोड एक अलग प्रदर्शन प्रोफ़ाइल के साथ चलाने के लिए जाता है चीजें जैसे चीजें।मैं एक डायनामिक मोड से आईएल बाइटियर कैसे प्राप्त करूं?

तो मैं निम्नलिखित कोड ::

Func<object,string> vs = x=>(string)x; 
Expression<Func<object,string>> exp = x=>(string)x; 
var compiled = exp.Compile(); 
Array.ForEach(vs.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine); 
Array.ForEach(compiled.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine); 

दुर्भाग्य से, यह एक अपवाद फेंकता के रूप में GetMethodBody जाहिरा तौर पर अभिव्यक्ति के पेड़ से उत्पन्न कोड पर एक अवैध संचालन है लिखा था। मैं लाइब्रेरी तरीके से कैसे कर सकता हूं (यानी बाहरी उपकरण के साथ नहीं जब तक टूल में एपीआई न हो) हल्के कोडजन का उपयोग करके कोड द्वारा उत्पन्न कोड को देखें?

संपादित करें: त्रुटि 5 पर संकलित होती है, compiled.Method.GetMethodBody() अपवाद फेंकता है।

संपादित 2: क्या कोई जानता है कि विधि में घोषित स्थानीय चर कैसे पुनर्प्राप्त करें? या GetVariables के लिए कोई रास्ता नहीं है?

+0

कौन सी लाइन अपवाद फेंक रही है? क्या आप पहले ऐरे को टिप्पणी कर सकते हैं। प्रत्येक के लिए और देखें कि क्या यह काम करता है?मुझे संदेह है कि GetMethodBody() को पहला कॉल बस विफल रहा है क्योंकि उस अभिव्यक्ति को आईएल में संकलित नहीं किया गया है। मुझे कोई कारण नहीं दिख रहा कि दूसरी कॉल क्यों विफल होनी चाहिए। – cdhowie

+0

दिलचस्प सवाल। मुझे GetMethodBody कॉल पर एक अवैधऑपरेशन अपवाद ("ऑब्जेक्ट की वर्तमान स्थिति के कारण वैध नहीं है") मिल रहा है। मुझे यकीन नहीं है कि कैसे कैश किए गए एनामीट डिलीगेट बनाम अभिव्यक्ति के रूप में जीवन शुरू करना आपके व्यवहार को एक Func के रूप में प्रभावित करेगा। मैं इसे काम करने के लिए जा रहा हूँ। – Sorax

+0

चयनित उत्तर को स्विच किया जाना चाहिए क्योंकि इसमें सभी मामलों को शामिल नहीं किया गया है और यह अनावश्यक रूप से जटिल है। कृपया [यह उत्तर] देखें (http://stackoverflow.com/a/35711507/521757)। – jnm2

उत्तर

16

हाँ, काम नहीं करता है, विधि प्रतिबिंब द्वारा उत्पन्न होती है। स्वीकार करें। आईएल को विधिबिल्डर के आईएलजीनरेटर में संग्रहीत किया जाता है। आप इसे खोद सकते हैं लेकिन आपको बहुत हताश होना है। आंतरिक और निजी सदस्यों को पाने के लिए प्रतिबिंब की आवश्यकता है। यह नेट 3.5SP1 पर काम किया:

using System.Linq.Expressions; 
using System.Reflection; 
using System.Reflection.Emit; 
... 

     var mtype = compiled.Method.GetType(); 
     var fiOwner = mtype.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic); 
     var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod; 
     var ilgen = dynMethod.GetILGenerator(); 
     var fiBytes = ilgen.GetType().GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic); 
     var fiLength = ilgen.GetType().GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic); 
     byte[] il = fiBytes.GetValue(ilgen) as byte[]; 
     int cnt = (int)fiLength.GetValue(ilgen); 
     // Dump <cnt> bytes from <il> 
     //... 

.NET 4.0 पर आप ilgen.GetType() का उपयोग करना होगा BaseType.GetField (...) क्योंकि आईएल जनरेटर बदल गया था, DynamicILGenerator, से ली गई। ILGenerator।

+0

यक! बहुत बहुत धन्यवाद! –

+0

ओह, अरे बदसूरत है। अच्छा काम ... यह शर्म की बात है कि कोड अधिक सुंदर नहीं हो सकता है। :( – cdhowie

+0

बस कोशिश की, यह .NET 4 में काम नहीं कर रहा है। यह मुझे बताता है कि फाइबेट्स शून्य है :( –

0

हंस Passant के काम बंद आधार पर मैं एक छोटे से गहरी वहाँ एक तरीका है कि आप कॉल करना चाहिए प्रतीत होता है खुदाई करने के लिए सक्षम था, BakeByteArray तो निम्न कार्य ::

var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod; 
var ilgen =dynamicMethod.GetILGenerator(); 
byte[] il = ilgen.GetType().GetMethod("BakeByteArray", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(ilgen, null) as byte[]; 

यह निश्चित रूप में मदद करता है अभी भी कहा जाता है, लेकिन मुझे लगता है VariableInfo's को हल करने का कोई तरीका नहीं है अभी तक ऐसा कुछ है जो मेरे काम में मदद करेगा।

+2

आप इसे दो बार बेक कर रहे हैं। सुनिश्चित नहीं है कि यह जला दिया जाता है, शायद नहीं। –

+0

मुझे यकीन नहीं है, हालांकि यह कोड पूरी तरह से बेकार है क्योंकि मैं इस दृष्टिकोण का उपयोग करके यथार्थवादी रूप से इसे अलग नहीं कर सकता क्योंकि मुझे मेटाडेटा नहीं मिल सकता है टोकन का कुछ भी उपयोगी हो गया है जो इस बात पर सूचीबद्ध मॉड्यूल के रूप में उपयोगी है । –

0

यहां वर्तमान समाधान .NET 4 में मौजूदा स्थिति बहुत अच्छी तरह से संबोधित कर नहीं कर रहे हैं। गतिशील विधि बनाने के लिए आप या तो DynamicILInfo या ILGenerator का उपयोग कर सकते हैं, लेकिन यहां सूचीबद्ध समाधान डायनामिक विधियों के साथ सभी पर काम नहीं करते हैं।

चाहे आप आईएल या ILGenerator विधि उत्पन्न करने के DynamicILInfo विधि का उपयोग करते हैं, आईएल बाइटकोड DynamicMethod.m_resolver.m_code में समाप्त होता है। आपको दोनों विधियों की जांच करने की आवश्यकता नहीं है और यह एक कम जटिल समाधान है।

public static byte[] GetILBytes(DynamicMethod dynamicMethod) 
{ 
    var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod); 
    if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized."); 
    return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver); 
} 

अधिक सहायक तरीकों के लिए See this answer और DynamicMethod टोकन संकल्प जारी करने के लिए एक समाधान:

इस संस्करण का उपयोग कर किया जाना चाहिए।

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