简体   繁体   English

Mono.Cecil:获取抽象方法的实现

[英]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查找抽象方法的实现?

1. Example of code to inspect 1.检查代码示例

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

2. The problem 2.问题

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

3. My question 3.我的问题

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一样使用堆栈来工作。

So, when you run line IL_0001 因此,当您运行IL_0001行时

Your stack will have 1 item, that is the instance of ImplementingType 您的堆栈将有1个项目,即ImplementingType的实例

Then you run IL_0006 然后您运行IL_0006

Your stack will have 0 items, and the instance of ImplementingType will be saved in first variable 您的堆栈将有0个项目,ImplementingType的实例将保存在第一个变量中

Then you run IL_0007 然后您运行IL_0007

Your stack will have 1 item again, that is the instance of ImplementingType 您的堆栈将再次具有1个项目,即ImplementingType的实例

Then you run IL_0008, 然后运行IL_0008,

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM