Давайте предположим, что у меня есть этот метод:Почему сохранение локальной переменной и ее чтение запускают функцию TargetInvocationException?
MethodBuilder doubleMethod = typeBuilder.DefineMethod("Double",
MethodAttributes.Public | MethodAttributes.Static,
typeof(int), new [] { typeof(int) });
ILGenerator il = countMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // We load the input argument (an int) into the evaluation stack
il.Emit(OpCodes.Ldc_I4_2); // We load the integer 2 into the evaluation stack
il.Emit(OpCodes.Mul); // We multiply both numbers (n * 2)
il.Emit(OpCodes.Ret); // We return what is left on the evaluation stack, i.e. the result of the multiplication
я могу назвать этот метод успешно:
Type type = typeBuilder.CreateType();
MethodInfo method = type.GetMethod("Double");
object result = method.Invoke(null, new object[] { 4 }); // result = 8
Однако, если я изменить IL код это:
il.Emit(OpCodes.Ldarg_0); // We load the input argument (an int) into the evaluation stack
il.Emit(OpCodes.Ldc_I4_2); // We load the integer 2 into the evaluation stack
il.Emit(OpCodes.Mul); // We multiply both numbers (n * 2)
/* I added these two instructions */
il.Emit(OpCodes.Stloc_0); // We pop the value from the evaluation stack and store into a local variable
il.Emit(OpCodes.Ldloc_0); // We read that local variable and push it back into the evaluation stack
il.Emit(OpCodes.Ret); // We return what is left on the evaluation stack, i.e. the result of the multiplication
При попытке для вызова сгенерированного метода выбрасывается следующее исключение:
Объект TargetInvocationException был необработанным - Исключение было выбрано целью вызова.
Почему это? Я имею в виду, выталкивая значение из оценочного стека, а затем снова нажимая одно и то же значение, должен делать абсурдно ничего. К моменту достижения значения OpCodes.Ret
правильное значение должно быть в стеке оценки.
Прежде чем вы получите в этом горячее и тяжелое, сначала поймите, как диагностировать исключение TargetInvocationException. У вас есть *, чтобы посмотреть на InnerException, чтобы узнать, что пошло не так. И используйте ILGenerator.DeclareLocal(), чтобы он мог правильно измерить требуемый размер стека. –
@HansPassant На самом деле, внутреннее исключение просто указывает, что «Common Language Runtime обнаружил недопустимую программу», я думал, что это слишком общее, чтобы найти его релевантным, и трассировка стека тоже не поможет. –
@HansPassant Добавление 'il.DeclareLocal (typeof (int))' сделал трюк! Спасибо! Можете ли вы опубликовать его как anwer? (Также, почему мне нужно вызвать этот метод?) –