簡體   English   中英

Mono.Cecil:在方法的開頭插入一條日志語句

[英]Mono.Cecil: Insert a log statement in method's beginning

我正在使用Mono.Cecil編輯目標方法的IL代碼,以便可以記錄該方法的入口點,而無需編輯實際代碼。 我能夠將調用指令插入可以執行記錄操作的方法。 但是我不知道如何記錄目標方法的輸入參數。 簡而言之,我想通過更改目標代碼的IL代碼在目標方法中插入一條指令來執行日志或說打印操作來記錄傳遞給該方法的輸入參數值。

我嘗試了一個基本程序作為示例。

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);
    }
}

好吧,這很有趣:)這是我的工作示例(代碼中的注釋,如果不清楚的話,可以隨意提問):

修改后的樣本(實際寫出參數):

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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM