gpt4 book ai didi

c# - Mono.Cecil:在方法的开头插入一条日志语句

转载 作者:行者123 更新时间:2023-11-30 20:31:39 26 4
gpt4 key购买 nike

我正在使用 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注入(inject)的源程序:

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

关于c# - Mono.Cecil:在方法的开头插入一条日志语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42891899/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com