如何在 IL 中的同一个 class 中调用方法
How do you invoke a method within the same class in IL
如果我正在编写代码,这将非常简单。我的代码看起来像:
public class SomeClass
{
public void SomeMethod(ISomeService someService)
{
}
private void AnotherMethod(ISomeService someService)
{
}
}
我可以通过类型引用获取这两种方法的方法定义,但我想要获取的是从 SomeMethod 到在 IL 中添加的 AnotherMethod 的调用,因此您将拥有类似的等效代码:
public void SomeMethod(ISomeService someService)
{
AnotherMethod(someService);
}
我现在完全迷失了试图理解如何正确构建必要的指令。
我现在拥有的看起来像:
private void ProcessType(TypeDefinition typeDef)
{
var anotherMethodDef = typeDef.Methods.FirstOrDefault(x => HasMethod(x, "AnotherMethod"));
if(someMethodDef != null)
{
var someMethodDef = typeDef.Methods.First(x => HasMethod(x, "SomeMethod"));
var processor = someMethodDef.Body.GetILProcessor();
// Now I need to generate:
// AnotherMethod(someService); as a new instruction
}
}
private static bool HasMethod(MethodDefinition method, string expected) =>
method.Name == expected && method.Parameters.Count() == 1 &&
method.Parameters.First().TypeDefinition.FullName == "Contoso.ISomeService";
不确定这是否有帮助,但是 SomeMethod
:
.maxstack 8
IL_0000: nop
IL_0001: ret
和 SomeMethod
的 IL 和 AnotherMethod(someService);
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call instance void SomeClass::AnotherMethod(class [YourAssembly]YourNamespace.ISomeService)
IL_0008: nop
IL_0009: ret
所以你想在中间添加这个:
// Add breakpoint space (
IL_0000: nop
// Load `this` (
IL_0001: ldarg.0
// Load your first argument... which is `someService`
IL_0002: ldarg.1
// Call method with this signature and previously loaded arguments
IL_0003: call instance void SomeClass::AnotherMethod(class [YourAssembly]YourNamespace.ISomeService)
最后这应该可以解决问题:
var myAssembly = Assembly.GetAssembly(typeof(SomeClass));
var module = myAssembly.MainModule;
var anotherMethodRef = module.Import(typeof(SomeClass).GetMethod("AnotherMethod", new[] { typeof(ISomeService) }));
var nop = processor.Create(OpCodes.Nop);
var loadThis = processor.Create(OpCodes.Ldarg_0);
var loadSomeService = processor.Create(OpCodes.Ldarg_1);
var callMethod = processor.Create(OpCodes.Call, anotherMethodRef);
// First instruction was IL_0000: nop
var firstInstruction = someMethodDef.Body.Instructions[0];
processor.InsertBefore(firstInstruction, nop);
processor.InsertBefore(firstInstruction, loadThis);
processor.InsertBefore(firstInstruction, loadSomeService);
processor.InsertBefore(firstInstruction, callMethod);
如果我正在编写代码,这将非常简单。我的代码看起来像:
public class SomeClass
{
public void SomeMethod(ISomeService someService)
{
}
private void AnotherMethod(ISomeService someService)
{
}
}
我可以通过类型引用获取这两种方法的方法定义,但我想要获取的是从 SomeMethod 到在 IL 中添加的 AnotherMethod 的调用,因此您将拥有类似的等效代码:
public void SomeMethod(ISomeService someService)
{
AnotherMethod(someService);
}
我现在完全迷失了试图理解如何正确构建必要的指令。
我现在拥有的看起来像:
private void ProcessType(TypeDefinition typeDef)
{
var anotherMethodDef = typeDef.Methods.FirstOrDefault(x => HasMethod(x, "AnotherMethod"));
if(someMethodDef != null)
{
var someMethodDef = typeDef.Methods.First(x => HasMethod(x, "SomeMethod"));
var processor = someMethodDef.Body.GetILProcessor();
// Now I need to generate:
// AnotherMethod(someService); as a new instruction
}
}
private static bool HasMethod(MethodDefinition method, string expected) =>
method.Name == expected && method.Parameters.Count() == 1 &&
method.Parameters.First().TypeDefinition.FullName == "Contoso.ISomeService";
不确定这是否有帮助,但是 SomeMethod
:
.maxstack 8
IL_0000: nop
IL_0001: ret
和 SomeMethod
的 IL 和 AnotherMethod(someService);
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call instance void SomeClass::AnotherMethod(class [YourAssembly]YourNamespace.ISomeService)
IL_0008: nop
IL_0009: ret
所以你想在中间添加这个:
// Add breakpoint space (
IL_0000: nop
// Load `this` (
IL_0001: ldarg.0
// Load your first argument... which is `someService`
IL_0002: ldarg.1
// Call method with this signature and previously loaded arguments
IL_0003: call instance void SomeClass::AnotherMethod(class [YourAssembly]YourNamespace.ISomeService)
最后这应该可以解决问题:
var myAssembly = Assembly.GetAssembly(typeof(SomeClass));
var module = myAssembly.MainModule;
var anotherMethodRef = module.Import(typeof(SomeClass).GetMethod("AnotherMethod", new[] { typeof(ISomeService) }));
var nop = processor.Create(OpCodes.Nop);
var loadThis = processor.Create(OpCodes.Ldarg_0);
var loadSomeService = processor.Create(OpCodes.Ldarg_1);
var callMethod = processor.Create(OpCodes.Call, anotherMethodRef);
// First instruction was IL_0000: nop
var firstInstruction = someMethodDef.Body.Instructions[0];
processor.InsertBefore(firstInstruction, nop);
processor.InsertBefore(firstInstruction, loadThis);
processor.InsertBefore(firstInstruction, loadSomeService);
processor.InsertBefore(firstInstruction, callMethod);