2017-03-19 6 views
0

Mono.Cecil을 사용하여 실제 메서드를 편집하지 않고 해당 메서드의 진입 점을 기록 할 수 있도록 대상 메서드의 IL 코드를 편집하고 있습니다. 로깅 작업을 수행 할 수있는 메소드에 호출 명령어를 삽입 할 수 있습니다. 그러나 대상 메서드의 입력 매개 변수를 기록하는 방법을 모르겠습니다. 간단히 말해서, 대상 메서드에 명령을 삽입하려면 IL 코드를 변경하여 로그를 수행하거나 인쇄 작업을 호출하여 해당 메서드에 전달 된 입력 매개 변수 값을 기록하십시오.Mono.Cecil : 메서드 시작 부분에 log 문을 삽입하십시오.

샘플로 기본 프로그램을 사용해 보았습니다.

public class Target 
{ 
    // My target method. 
    public void Run(int arg0, string arg1) 
    { 
     Console.WriteLine("Run method body"); 
    } 


} 

public static class Trace{ 

// This is my log method, which i want to call in begining of Run() method. 
    public void LogEntry(string methodName, object[] params) 
    { 
     System.Console.WriteLine("******Entered in "+ methodName+" method.***********") 
    // With params :...... 
    // 
    } 
} 

소스 프로그램.

public class Sample 
{ 
    private readonly string _targetFileName; 
    private readonly ModuleDefinition _module; 

    public ModuleDefinition TargetModule { get { return _module; } } 

    public Sample(string targetFileName) 
    { 
     _targetFileName = targetFileName; 

     // Read the module with default parameters 
     _module = ModuleDefinition.ReadModule(_targetFileName); 
    } 

    public void Run(string type, string method) 
    { 

     // Retrive the target class. 
     var targetType = _module.Types.Single(t => t.Name == type); 

     // Retrieve the target method. 
     var runMethod = targetType.Methods.Single(m => m.Name == method); 

     // Get a ILProcessor for the Run method 
     var processor = runMethod.Body.GetILProcessor(); 

     // get log entry method ref to create instruction 
     var logEntryMethodReference = targetType.Methods.Single(m => m.Name == "LogEntry"); 

    // Import .. 
    // 
     var newInstruction = processor.Create(OpCodes.Call, logEntryMethodReference); 

     var firstInstruction = runMethod.Body.Instructions[0]; 

     processor.InsertBefore(firstInstruction, newInstruction); 

     // Write the module with default parameters 
     _module.Write(_targetFileName); 
    } 
} 
+0

이것은 가출 소리 ting,하지만 일부 샘플 코드가 없으면 우리 중 누구도 도움을 줄 수 없다고 생각합니다 :) 지금까지 가지고있는 것을 게시하십시오 (그리고 호색하지 않아도되지만, 이것은 보통 여러분이 가지고있는 모든 질문에 대해 사실입니다. 지금; 다른 사람, 덜 이해하는 사람들은 이러한 질문에 대한 소스 코드가 누락 된 경우에도 부정 투표를 할 수 있습니다.) –

+0

@Akos 업데이트했습니다. – Krishnan

+0

괜찮습니까? 여기서'targetType'은'Target'이지만'LogEntry' 메쏘드는'Trace' 클래스에 있습니다 (클래스와 메쏘드는 정적이어야합니다). 'targetType.Methods.Single()'을 실행하고'LogEntry'를 찾으면, 그것은'Trace'가 아니라'Target'에서 메소드를 찾습니다. 또는 나는 무엇인가 놓치고 있냐? –

답변

2

글쎄,이 흥미로웠다 :) 가 여기 내 작업 예제 (코드에 주석, 명확하지 않을 경우 아무것도 묻지 부담)입니다 :

수정 된 샘플 (실제로 매개 변수를 쓰기에) :

public class Target 
{ 
    // My target method. 
    public void Run(int arg0, string arg1) 
    { 
     Console.WriteLine("Run method body"); 
    } 

} 

public static class Trace 
{ 

    // This is my log method, which i want to call in begining of Run() method. 
    public static void LogEntry(string methodName, object[] parameters) 
    { 
     Console.WriteLine("******Entered in " + methodName + " method.***********"); 
     Console.WriteLine(parameters[0]); 
     Console.WriteLine(parameters[1]); 
    } 
} 

소스 프로그램 IL 주입을 처리하기 :

public class Sample 
{ 
    private readonly string _targetFileName; 
    private readonly ModuleDefinition _module; 

    public ModuleDefinition TargetModule { get { return _module; } } 

    public Sample(string targetFileName) 
    { 
     _targetFileName = targetFileName; 

     // Read the module with default parameters 
     _module = ModuleDefinition.ReadModule(_targetFileName); 
    } 

    public void Run(string type, string method) 
    { 

     // Retrive the target class. 
     var targetType = _module.Types.Single(t => t.Name == type); 

     // Retrieve the target method. 
     var runMethod = targetType.Methods.Single(m => m.Name == method); 

     // Get a ILProcessor for the Run method 


     // get log entry method ref to create instruction 
     var logEntryMethodReference = _module.Types.Single(t => t.Name == "Trace").Methods.Single(m => m.Name == "LogEntry"); 


     List<Instruction> newInstructions = new List<Instruction>(); 


     var arrayDef = new VariableDefinition(new ArrayType(_module.TypeSystem.Object)); // create variable to hold the array to be passed to the LogEntry() method    
     runMethod.Body.Variables.Add(arrayDef); // add variable to the method   

     var processor = runMethod.Body.GetILProcessor(); 

     newInstructions.Add(processor.Create(OpCodes.Ldc_I4, runMethod.Parameters.Count)); // load to the stack the number of parameters      
     newInstructions.Add(processor.Create(OpCodes.Newarr, _module.TypeSystem.Object)); // create a new object[] with the number loaded to the stack   
     newInstructions.Add(processor.Create(OpCodes.Stloc, arrayDef)); // store the array in the local variable 

     // loop through the parameters of the method to run 
     for (int i = 0; i < runMethod.Parameters.Count; i++) 
     { 
      newInstructions.Add(processor.Create(OpCodes.Ldloc, arrayDef)); // load the array from the local variable 
      newInstructions.Add(processor.Create(OpCodes.Ldc_I4, i)); // load the index 
      newInstructions.Add(processor.Create(OpCodes.Ldarg, i+1)); // load the argument of the original method (note that parameter 0 is 'this', that's omitted) 

      if (runMethod.Parameters[i].ParameterType.IsValueType) 
      { 
       newInstructions.Add(processor.Create(OpCodes.Box, runMethod.Parameters[i].ParameterType)); // boxing is needed for value types 
      } 
      else 
      { 
       newInstructions.Add(processor.Create(OpCodes.Castclass, _module.TypeSystem.Object)); // casting for reference types 
      } 
      newInstructions.Add(processor.Create(OpCodes.Stelem_Ref)); // store in the array 
     } 

     newInstructions.Add(processor.Create(OpCodes.Ldstr, method)); // load the method name to the stack 
     newInstructions.Add(processor.Create(OpCodes.Ldloc, arrayDef)); // load the array to the stack 
     newInstructions.Add(processor.Create(OpCodes.Call, logEntryMethodReference)); // call the LogEntry() method 


     foreach (var newInstruction in newInstructions.Reverse<Instruction>()) // add the new instructions in referse order 
     { 
      var firstInstruction = runMethod.Body.Instructions[0]; 
      processor.InsertBefore(firstInstruction, newInstruction); 
     } 

     // Write the module with default parameters 
     _module.Write(_targetFileName); 
    } 
}