[英]Mono.Cecil: get implementation of abstract method
I'm using Cecil to inspect my program. 我正在使用Cecil检查我的程序。 It is working really great with one exception.
除了一个例外,它的运行情况非常好。 How can I use Cecil to find the implementation of an abstract method?
如何使用Cecil查找抽象方法的实现?
This is an example of code where the method CallingType::CallAbstractMethod() makes a call to ImplementingType::MyMethod() . 这是代码示例,其中方法CallingType :: CallAbstractMethod()调用ImplementingType :: MyMethod() 。
public abstract class AbstractBase
{
public abstract bool MyMethod();
}
public class ImplementingType : AbstractBase
{
public override bool MyMethod()
{
return true;
}
}
public class CallingType
{
public void CallAbstractMethod()
{
var implementingType = new ImplementingType();
var result = implementingType.MyMethod();
}
}
When I use the Cecil code below to inspect my program the variable myMethodDefinition represents the abstract method AbstractBase::MyMethod() instead of ImplementingType::MyMethod() . 当我使用下面的Cecil代码检查程序时,变量myMethodDefinition表示抽象方法AbstractBase :: MyMethod()而不是ImplementingType :: MyMethod() 。 The later is the method that I would like to find.
稍后是我想找到的方法。 Just reading the source code it is obvious that the method CallAbstractMethod is actually calling ImplementingType::MyMethod() .
仅阅读源代码,很明显方法CallAbstractMethod实际上是在调用ImplementingType :: MyMethod() 。
var assembly = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
var callingType = assembly.MainModule.Types
.Single(t => t.Name == "CallingType");
var callAbstractMethodDefinition = callingType.Methods
.Single(m => m.Name == "CallAbstractMethod");
var myMethodReference = callAbstractMethodDefinition.Body.Instructions
.Where(i => i.OpCode == OpCodes.Callvirt)
.Select(i => (MethodReference)i.Operand)
.Single();
var myMethodDefinition = myMethodReference.Resolve();
What can I do to get my Cecil code to find the implementing method ImplementingType::MyMethod() ? 我该怎么做才能让我的Cecil代码找到实现方法ImplementingType :: MyMethod() ?
The IL from CallAbstractMethod CallAbstractMethod的IL
.method public hidebysig
instance void CallAbstractMethod () cil managed
{
// Method begins at RVA 0x2078
// Code size 15 (0xf)
.maxstack 1
.locals init (
[0] class ConsoleApplication1.ImplementingType, //first variable
[1] bool
)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.ImplementingType::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance bool ConsoleApplication1.AbstractBase::MyMethod()
IL_000d: stloc.1
IL_000e: ret
} // end of method CallingType::CallAbstractMethod
As you can see, the callvirt OpCode is calling base class, if you want to get the real class that hold the implementation of MyMethod you must work like IL works, using stack. 如您所见,callvirt OpCode正在调用基类,如果要获取保存MyMethod实现的真实类,则必须像IL一样使用堆栈来工作。
Your stack will have 1 item, that is the instance of ImplementingType
您的堆栈将有1个项目,即ImplementingType的实例
Your stack will have 0 items, and the instance of ImplementingType will be saved in first variable
您的堆栈将有0个项目,ImplementingType的实例将保存在第一个变量中
Your stack will have 1 item again, that is the instance of ImplementingType
您的堆栈将再次具有1个项目,即ImplementingType的实例
Call MyMethod from first item in the stack, that is the instance of ImplementingType.
从堆栈的第一项(即ImplementingType的实例)调用MyMethod。
So there is no way to get reference to ImplementingType just with the line IL_0008, you must "execute" the code, fake stack process and then you will be able to discover the instanced that hold the method that will execute. 因此,仅凭IL_0008行就无法获得对ImplementingType的引用,您必须“执行”代码,伪造堆栈过程,然后才能发现包含将要执行的方法的实例。
The same code could be optimized, see it below: 可以优化相同的代码,请参见下面的代码:
.method public hidebysig
instance void CallAbstractMethod () cil managed
{
// Method begins at RVA 0x2065
// Code size 12 (0xc)
.maxstack 8
IL_0000: newobj instance void ConsoleApplication1.ImplementingType::.ctor()
IL_0005: callvirt instance bool ConsoleApplication1.AbstractBase::MyMethod()
IL_000a: pop
IL_000b: ret
} // end of method CallingType::CallAbstractMethod
I don't know what you want to do with this, but you have the solution, csprojs, and c# class files, and you want to read the code, I would suggest you to use Roslyn to do that. 我不知道您想怎么做,但是您拥有解决方案,csprojs和c#类文件,并且您想阅读代码,我建议您使用Roslyn来做到这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.