Das Hinzufügen von Ausnahme-Handlern mit Mono.Cecil ist nicht schwierig, es erfordert nur, dass Sie wissen, wie Exception-Handler in den Metadaten angeordnet sind.
Lassen Sie sagen, Sie die C# Methode haben:
static void Throw()
{
throw new Exception ("oups");
}
Wenn Sie es dekompilieren, sollte es dazu etwas ähnlich aussehen:
.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
}
Nun lassen Sie sagen, dass Sie Code in diese injizieren wollen Verfahren wie es ist ähnlich wie der C# -Code:
static void Throw()
{
try {
throw new Exception ("oups");
} catch (Exception e) {
Console.WriteLine (e);
}
}
das heißt, wollen Sie einfach den vorhandenen Code umwickeln ein Versuch, Catch-Handler. Sie können es mit Cecil tun einfach so:
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);
Dieser Code die bisherige Methode manipuliert wie folgt aussehen:
.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
}
Wir fügen drei neue Anweisungen: Anruf an Console.WriteLine , ein Verlassen, um den Fanghandhaber zu verlassen, und schließlich (Wortspiel beabsichtigt), ein ret. Dann erstellen wir einfach eine ExceptionHandler-Instanz, die einen try catch-Handler darstellt, dessen try den vorhandenen body umfasst und dessen catch die WriteLine-Anweisung ist.
Eine wichtige Sache zu beachten ist, dass die Endeanweisung eines Bereichs nicht innerhalb des Bereichs enthalten ist. Es ist im Grunde ein [TryStart: TryEnd [Bereich.
Der Steuerungsfluss darf nicht aus einem solchen Catch-Handler herausfallen. ECMA-335, §12.4.2.8.1 "Exit von geschützten Blöcken, Filtern oder Handlern kann nicht durch Durchfallen erreicht werden." (Obwohl die Microsoft CLR diese Regel nicht zu erzwingen scheint) – Daniel
@Daniel, guter Fang, lass mich den fehlenden Urlaub hinzufügen. Danke für die Köpfe hoch. –
danke für diese schnelle antwort! funktioniert gut - und so einfach! vielen Dank! – cyptus