Mono.Cecil での try/catch の実装の概要はここで回答されましたが、完全な try/catch/finally のすぐ手前で停止します。では、Mono.Cecil を使用して try/finally を実装するにはどうすればよいでしょうか。
質問する
2111 次
2 に答える
10
最終的に注入する方法は次のとおりです。
まず、return ステートメントを修正する必要があります。欲しいのは1つだけです。
Instruction FixReturns()
{
if (Method.ReturnType == TypeSystem.Void)
{
var instructions = body.Instructions;
var lastRet = Instruction.Create(OpCodes.Ret);
instructions.Add(lastRet);
for (var index = 0; index < instructions.Count - 1; index++)
{
var instruction = instructions[index];
if (instruction.OpCode == OpCodes.Ret)
{
instructions[index] = Instruction.Create(OpCodes.Leave, lastRet);
}
}
return lastRet;
}
else
{
var instructions = body.Instructions;
var returnVariable = new VariableDefinition("methodTimerReturn", Method.ReturnType);
body.Variables.Add(returnVariable);
var lastLd = Instruction.Create(OpCodes.Ldloc, returnVariable);
instructions.Add(lastLd);
instructions.Add(Instruction.Create(OpCodes.Ret));
for (var index = 0; index < instructions.Count - 2; index++)
{
var instruction = instructions[index];
if (instruction.OpCode == OpCodes.Ret)
{
instructions[index] = Instruction.Create(OpCodes.Leave, lastLd);
instructions.Insert(index, Instruction.Create(OpCodes.Stloc, returnVariable));
index++;
}
}
return lastLd;
}
}
次に、最初の指示を見つけます。インスタンス コンストラクターの場合は 2 をスキップする必要があります。
Instruction FirstInstructionSkipCtor()
{
if (Method.IsConstructor && !Method.IsStatic)
{
return body.Instructions.Skip(2).First();
}
return body.Instructions.First();
}
それからそれを一緒に縫います
void InnerProcess()
{
body = Method.Body;
body.SimplifyMacros();
ilProcessor = body.GetILProcessor();
var returnInstruction = FixReturns();
var firstInstruction = FirstInstructionSkipCtor();
var beforeReturn = Instruction.Create(OpCodes.Nop);
ilProcessor.InsertBefore(returnInstruction, beforeReturn);
InjectIlForFinaly(returnInstruction);
var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
{
TryStart = firstInstruction,
TryEnd = beforeReturn,
HandlerStart = beforeReturn,
HandlerEnd = returnInstruction,
};
body.ExceptionHandlers.Add(handler);
body.InitLocals = true;
body.OptimizeMacros();
}
于 2012-10-09T10:43:30.950 に答える
1
チェックされた例は非常に有益で有用であることがわかりました。ただし、より複雑な条件で問題が発生しました。FixReturns() では、void と非 void の両方の戻りスコープで、ret を変更する方法 -> 新しい命令の作成によって元の命令が孤立します。これにより、オーファンをオペランドとして持つ他の命令が残る可能性があります (たとえば、元の ret への分岐)。結果のコードは無効になります。
既存の ret 命令のオペコード/オペランドのペアを更新しただけで、新しいものを作成しただけで、すべて問題なく表示されます。
乾杯。
于 2016-04-03T22:06:22.103 に答える