Thêm trình xử lý ngoại lệ bằng Mono.Cecil không khó, nó chỉ yêu cầu bạn biết cách trình xử lý ngoại lệ được trình bày trong siêu dữ liệu.
Hãy nói rằng bạn có C# phương pháp:
static void Throw()
{
throw new Exception ("oups");
}
Nếu bạn dịch ngược nó, nó nên nhìn hơi tương tự như sau:
.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
}
Bây giờ hãy nói rằng bạn muốn tiêm mã trong này phương pháp như nó tương tự như mã C#:
static void Throw()
{
try {
throw new Exception ("oups");
} catch (Exception e) {
Console.WriteLine (e);
}
}
Tức là, bạn chỉ muốn bao bọc mã hiện tại một thử xử lý bắt. Bạn có thể làm điều đó một cách dễ dàng với Cecil theo cách này:
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);
Mã này được thao tác phương pháp trước đó trông như thế này:
.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
}
Chúng tôi đang thêm ba hướng dẫn mới: một cuộc gọi đến Console.WriteLine , để lại một cách duyên dáng thoát khỏi xử lý bắt, và cuối cùng (chơi chữ dự định), một ret. Sau đó, chúng tôi chỉ đơn giản là tạo ra một trường hợp ExceptionHandler để đại diện cho một trình xử lý bắt thử mà cố gắng bao gồm cơ thể hiện có, và bắt của nó là câu lệnh WriteLine.
Một điều quan trọng cần lưu ý là lệnh kết thúc của một phạm vi không được chứa trong phạm vi. Về cơ bản nó là [TryStart: TryEnd [range.
Luồng điều khiển không được phép rơi ra khỏi trình xử lý bắt được như vậy. ECMA-335, §12.4.2.8.1 "Thoát khỏi các khối, bộ lọc hoặc trình xử lý được bảo vệ không thể thực hiện được thông qua mùa thu". (mặc dù CLR của Microsoft dường như không thực thi quy tắc này) – Daniel
@Daniel, bắt tốt, hãy để tôi thêm thời gian nghỉ còn thiếu. Cảm ơn cho những người đứng đầu lên. –
cảm ơn câu trả lời nhanh này! làm việc tốt - và dễ dàng như vậy! Cảm ơn nhiều! – cyptus