2012-10-07 4 views

답변

8

마지막으로 주사하는 방법입니다.

먼저 신고서를 수정해야합니다. 너는 오직 하나만 원한다.

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(); 
} 
+0

그래서 기본적으로 ExceptionHandlerType.Finally를 새로운 ExceptionHandler()에 전달하여 해당 게시물에 설명 된 것과 동일한 프로세스입니다. try/catch/finally를 원한다면 두 개의 "ExceptionHandler"인스턴스를 만들어 메소드에 추가합니다. 하나는 catch를위한 인스턴스이고, 하나는 finally를위한 것입니다. 이 경우, 적어도 'finally'를 위해 새로운 예외 처리기를 실제로 만들지 않으므로 이름이 확실히 혼란 스럽습니다. 포인터를 가져 주셔서 감사합니다. – naasking

1

를 스티치. 더 복잡한 조건에서 문제가 발생 했습니까? FixReturns()에서 보이드 및 비 보이드 반환 범위 모두에서 새로운 명령 작성을 통한 ret -> leave 변경 방법은 원본을 고아가됩니다. 이는 고아가있는 다른 명령어를 피연산자로 남겨 둘 수 있습니다 (예 : 원본 ret로 분기). 그런 다음 결과 코드가 유효하지 않게됩니다.

기존의 ret 명령어의 opcode/operand 쌍 대 새로운 명령어 생성자 쌍을 업데이트하여 모두 잘 나타납니다.

건배.