【发布时间】:2012-09-27 23:51:13
【问题描述】:
很好地概述了在 Mono.Cecil was answered here 中实现 try/catch,但他在没有完整的 try/catch/finally 时就停了下来。那么如何使用 Mono.Cecil 实现 try/finally?
【问题讨论】:
标签: .net mono.cecil
很好地概述了在 Mono.Cecil was answered here 中实现 try/catch,但他在没有完整的 try/catch/finally 时就停了下来。那么如何使用 Mono.Cecil 实现 try/finally?
【问题讨论】:
标签: .net mono.cecil
这里是如何注入 finally。
首先,您需要修正您的退货声明。你只想要一个。
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();
}
【讨论】:
发现检查的示例非常有用且非常有用。但是,在更复杂的条件下确实遇到了问题。在 FixReturns() 中,无论是 void 还是非 void 返回范围,通过创建新指令来更改 ret -> leave 的方法都会孤立原件。这可以将其他指令与孤儿作为操作数(例如,分支到原始 ret)。结果代码最终无效。
我们只是更新了现有的 ret 指令的操作码/操作数对,而不是创建新的,一切看起来都很好。
干杯。
【讨论】: