Этот вопрос касается статического анализа стека пользовательского кода C # IL и того, как разработать коды операций для удовлетворения требований компилятора.
У меня есть код, который изменяет существующие методы C #, добавляя к нему мой собственный код. Чтобы избежать возврата исходного метода до выполнения моего кода, он заменяет все коды операций RET на конечную метку BR и добавляет эту метку в конец исходного кода. Затем я добавляю туда еще код и, наконец, RET.
В целом все это работает нормально, но не работает с некоторыми методами. Вот простой пример:
public static string SomeMethod(int val)
{
switch (val)
{
case 0:
return "string1".convert();
case 1:
return "string2".convert();
case 2:
return "string3".convert();
// ...
}
return "";
}
который представлен этим кодом IL:
.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
}
После того, как моя программа изменила его, код выглядит так:
.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
}
и я получаю ошибку компиляции:
Не удалось выполнить действие после длительного события. Исключение: System.TypeInitializationException: исключение было создано инициализатором типа для FooBar ---> System.InvalidProgramException: недопустимый код IL в (динамический метод оболочки) Foo: SomeMethod (int): IL_0000: ldnull
Есть ли какой-нибудь простой способ заменить RET обычным способом и сделать так, чтобы статический анализатор остался доволен?