Diese Frage bezieht sich auf statische Stack-Analyse von benutzerdefinierten C# IL-Code und wie die Opcodes den Compiler zu erfüllen.C# IL-Code-Änderung - Stapel intakt halten
Ich habe Code, der vorhandene C# -Methoden ändert, indem ich meinen eigenen Code an ihn anfüge. Um zu vermeiden, dass die ursprüngliche Methode zurückkehrt, bevor mein Code ausgeführt wird, ersetzt sie alle Opcodes RET durch eine BR Endlabel und fügt dieses Etikett am Ende des ursprünglichen Codes hinzu. Ich füge dann mehr Code hinzu und schließlich einen RET.
Das alles funktioniert im Allgemeinen gut, aber auf bestimmte Methoden fehlschlägt. Hier ist ein einfaches Beispiel:
public static string SomeMethod(int val)
{
switch (val)
{
case 0:
return "string1".convert();
case 1:
return "string2".convert();
case 2:
return "string3".convert();
// ...
}
return "";
}
, die durch diesen IL-Code dargestellt wird:
.method public hidebysig static string SomeMethod(int32 val) cil managed
{
.maxstack 1
.locals val ([0] int32 num)
L_0000: ldarg.0
L_0001: stloc.0
L_0002: ldloc.0
L_0003: switch (L_002e, L_004f, L_0044, ...)
L_002c: br.s L_0091
L_002e: ldstr "string1"
L_0033: call string Foo::convert(string)
L_0038: ret
L_0039: ldstr "string2"
L_003e: call string Foo::convert(string)
L_0043: ret
L_0044: ldstr "string3"
L_0049: call string Foo::convert(string)
L_004e: ret
...
L_0091: ldstr ""
L_0096: ret
}
Nach meinem Programm es geändert, der Code sieht wie folgt aus:
.method public hidebysig static string SomeMethod(int32 val) cil managed
{
.maxstack 1
.locals val ([0] int32 num)
L_0000: ldarg.0
L_0001: stloc.0
L_0002: ldloc.0
L_0003: switch (L_002e, L_004f, L_0044, ...)
L_002c: br.s L_0091
L_002e: ldstr "string1"
L_0033: call string Foo::convert(string)
L_0038: br L_009b // was ret
L_0039: ldstr "string2"
L_003e: call string Foo::convert(string)
L_0043: br L_009b // was ret
L_0044: ldstr "string3"
L_0049: call string Foo::convert(string)
L_004e: br L_009b // was ret
...
L_0091: ldstr ""
L_0096: br L_009b // was ret
L_009b: my code here
...
L_0200: ret
}
und ich ein Kompilierfehler:
Could not execute post-long-event action. Exception: System.TypeInitializationException: An exception was thrown by the type initializer for FooBar ---> System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) Foo:SomeMethod (int): IL_0000: ldnull
Gibt es eine einfache Möglichkeit, RETs auf generische Weise zu ersetzen und den statischen Analyzer glücklich zu machen?
Das Problem wurde behoben. Ersetzen von RET mit BR erhöht die Codelänge und kurze Sprünge können möglicherweise illegal werden. Die Lösung besteht darin, sie durch lange Sprünge zu ersetzen. Getestet und funktioniert. –
Sie könnten auch eine try-finally-Klausel verwenden. das wird all deine Probleme vermeiden. Natürlich macht es nur Sinn, wenn Sie * immer * diesen Code ausführen wollen - er wird auch bei einer Exception ausgeführt. Je nachdem, welchen Code du eingibst, kann das eine gute Sache oder eine schlechte Sache sein. – Luaan
Guter Fang auf Ihrem eigenen Fehler :) Sie sollten auf sich selbst antworten –