Возможный дубликат:
Mono.Cecil позаботится о филиалах и т. д.?
Я работаю над проектом, который требует, чтобы я вставил вызов статического метода после вызова определенных методов в моем приложении. Я использую для этого Mono Cecil, и по большей части все работает нормально. Однако я сталкиваюсь с некоторыми случаями, когда смещения ветвей искажаются, когда обновленная сборка записывается на диск. Вот как выглядит мой код:
public void InstrumentMethod(MethodDefinition method) { var processor = method.Body.GetILProcessor(); var instr = GetStaticInstrumentMethod(); var instrument = method.Module.Import(instr); var call = method.Body.Instructions.First(i => i.IsCallImInterestedIn()); processor.InsertBefore(call, instrument); }
Таким образом, в 90% случаев этот код работает без проблем — целевой метод оснащен моим дополнительным вызовом, и все работает нормально.
В остальных 10% случаев инструментированный метод не может быть выполнен, и я получаю ошибки, пытаясь просмотреть его в ILSpy. Ошибка ILSpy:
ICSharpCode.Decompiler.DecompilerException: Error decompiling System.Object Savo.Utilities.Mapping.ReflectionMapper::MapTo(System.Object,System.Object) ---> System.NullReferenceException: Object reference not set to an instance of an object. at ICSharpCode.Decompiler.ILAst.ILAstBuilder.c__DisplayClass33.b__26(ByteCode b) at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate) at ICSharpCode.Decompiler.ILAst.ILAstBuilder.ConvertLocalVariables(List`1 body) at ICSharpCode.Decompiler.ILAst.ILAstBuilder.StackAnalysis(MethodDefinition methodDef) at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(IEnumerable`1 parameters) at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable`1 parameters) --- End of inner exception stack trace --- at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable`1 parameters) at ICSharpCode.Decompiler.Ast.AstBuilder.CreateMethod(MethodDefinition methodDef) at ICSharpCode.ILSpy.CSharpLanguage.DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) at ICSharpCode.ILSpy.TextView.DecompilerTextView.DecompileNodes(DecompilationContext context, ITextOutput textOutput) at ICSharpCode.ILSpy.TextView.DecompilerTextView.c__DisplayClass10.b__f()
Я декомпилировал код с помощью ildasm и заметил, что возникают проблемы с обновлением смещений при сохранении сборки. Я ничего не делал со смещениями вызова (пытался установить их вручную, но видел те же проблемы). Предварительная приборная разборка для одного из моих проблемных методов выглядит так:
IL_000e: br.s IL_005e
IL_0010: ldloca.s CS$5$0000
IL_0012: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class MyThing>::get_Current()
IL_0017: stloc.0
IL_0018: nop
... business logic ...
IL_005d: nop
IL_005e: ldloca.s CS$5$0000
IL_0060: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class MyThing>::MoveNext()
IL_0065: stloc.3
IL_0066: ldloc.3
IL_0067: brtrue.s IL_0010
IL_0069: leave.s IL_007a
Когда я смотрю на инструментальный дизассемблирование, строка, соответствующая IL_0067 в этом примере, выглядит так:
IL_00bc: brtrue.s IL_0129
который не может быть скомпилирован, так как IL_0129 не существует в текущем методе.
Я заметил, но еще не доказал, что это происходит только вокруг итераторов. Код C# для двух случаев, когда это происходит до сих пор, был циклами foreach, и обе неверные цели ветвления, по-видимому, связаны с конечным условием циклов foreach.
Итак, мой вопрос: мне нужно вручную управлять ссылками смещения, или я что-то еще делаю неправильно?