2012-06-17 8 views
8

के साथ एक प्रयास-पकड़ जोड़ें मैं एक और विधि में कोड इंजेक्ट करने के लिए मोनो सेसिल का उपयोग कर रहा हूं। मैं अपने कोड के चारों ओर एक कोशिश-पकड़ ब्लॉक जोड़ना चाहता हूं।मोनो सेसिल

इसलिए मैंने एक हैलोवर्ल्ड.एक्सई को एक कोशिश पकड़ ब्लॉक के साथ लिखा और इसे संकुचित कर दिया।

कोशिश-पकड़ने के लिए परावर्तक में इस तरह दिखता है:

.try L_0001 to L_0036 catch [mscorlib]System.Exception handler L_0036 to L_003b 

कैसे मैं मोनो सेसिल के माध्यम से इस तरह एक कोशिश पकड़ इंजेक्षन कर सकते हैं?

उत्तर

19

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

माना कि आप सी # विधि है:

static void Throw() 
{ 
    throw new Exception ("oups"); 
} 

आप इसे डिकंपाइल हैं, तो यह कुछ हद तक इस के समान दिखना चाहिए:

.method private static hidebysig default void Throw() cil managed 
{ 
    IL_0000: ldstr "oups" 
    IL_0005: newobj instance void class [mscorlib]System.Exception::.ctor(string) 
    IL_000a: throw 
} 

अब कहना है कि आप इस में कोड इंजेक्षन करना चाहते हैं विधि जैसे कि यह सी # कोड के समान है:

static void Throw() 
{ 
    try { 
     throw new Exception ("oups"); 
    } catch (Exception e) { 
     Console.WriteLine (e); 
    } 
} 

यही है, आप बस मौजूदा कोड को लपेटना चाहते हैं एक कोशिश पकड़ने वाले हैंडलर।

var method = ...; 
    var il = method.Body.GetILProcessor(); 

    var write = il.Create (
     OpCodes.Call, 
     module.Import (typeof (Console).GetMethod ("WriteLine", new [] { typeof (object)}))); 
    var ret = il.Create (OpCodes.Ret); 
    var leave = il.Create (OpCodes.Leave, ret); 

    il.InsertAfter (
     method.Body.Instructions.Last(), 
     write); 

    il.InsertAfter (write, leave); 
    il.InsertAfter (leave, ret); 

    var handler = new ExceptionHandler (ExceptionHandlerType.Catch) { 
     TryStart = method.Body.Instructions.First(), 
     TryEnd = write, 
     HandlerStart = write, 
     HandlerEnd = ret, 
     CatchType = module.Import (typeof (Exception)), 
    }; 

    method.Body.ExceptionHandlers.Add (handler); 

इस कोड को इस तरह देखने के लिए पिछले विधि से छेड़छाड़ कर रहा है:

.method private static hidebysig default void Throw() cil managed 
{ 
    .maxstack 1 
    .try { // 0 
     IL_0000: ldstr "oups" 
     IL_0005: newobj instance void class [mscorlib]System.Exception::'.ctor'(string) 
     IL_000a: throw 
    } // end .try 0 
    catch class [mscorlib]System.Exception { // 0 
     IL_000b: call void class [mscorlib]System.Console::WriteLine(object) 
     IL_0010: leave IL_0015 
    } // end handler 0 
    IL_0015: ret 
} 

हम तीन नए निर्देश जोड़ रहे हैं: आप इसे आसानी से सेसिल के साथ इस तरह से कर सकते हैं Console.WriteLine के लिए एक कॉल , पकड़ने वाले हैंडलर से बाहर निकलने के लिए एक छुट्टी, और अंत में (पन इरादा), एक ret। फिर हम एक प्रयास कैप्चर हैंडलर का प्रतिनिधित्व करने के लिए एक अपवाद हैंडलर उदाहरण बना रहे हैं जिसका प्रयास मौजूदा निकाय को शामिल करता है, और जिसका पकड़ लिखित रेखा है।

ध्यान देने योग्य एक महत्वपूर्ण बात यह है कि सीमा के अंत निर्देश सीमा के अंदर निहित नहीं है। यह मूल रूप से एक [TryStart: TryEnd [रेंज है।

+2

नियंत्रण प्रवाह को कैच हैंडलर से बाहर निकलने की अनुमति नहीं है। ईसीएमए -335, §12.4.2.8.1 "संरक्षित ब्लॉक, फ़िल्टर, या हैंडलर से बाहर निकलने के माध्यम से गिरने के माध्यम से पूरा नहीं किया जा सकता है।" (हालांकि माइक्रोसॉफ्ट सीएलआर इस नियम को लागू नहीं कर रहा है) – Daniel

+0

@ डैनियल, अच्छी पकड़, मुझे लापता छुट्टी जोड़ने दो। सर उठाने के लिए धन्यवाद। –

+1

इस तेजी से उत्तर के लिए धन्यवाद! ठीक काम कर रहा है - और इतना आसान! आपका बहुत बहुत धन्यवाद! – cyptus

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