簡體   English   中英

Mono.Cecil:獲取抽象方法的實現

[英]Mono.Cecil: get implementation of abstract method

我正在使用Cecil檢查我的程序。 除了一個例外,它的運行情況非常好。 如何使用Cecil查找抽象方法的實現?

1.檢查代碼示例

這是代碼示例,其中方法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.問題

當我使用下面的Cecil代碼檢查程序時,變量myMethodDefinition表示抽象方法AbstractBase :: MyMethod()而不是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.我的問題

我該怎么做才能讓我的Cecil代碼找到實現方法ImplementingType :: MyMethod()

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

如您所見,callvirt OpCode正在調用基類,如果要獲取保存MyMethod實現的真實類,則必須像IL一樣使用堆棧來工作。

因此,當您運行IL_0001行時

您的堆棧將有1個項目,即ImplementingType的實例

然后您運行IL_0006

您的堆棧將有0個項目,ImplementingType的實例將保存在第一個變量中

然后您運行IL_0007

您的堆棧將再次具有1個項目,即ImplementingType的實例

然后運行IL_0008,

從堆棧的第一項(即ImplementingType的實例)調用MyMethod。

因此,僅憑IL_0008行就無法獲得對ImplementingType的引用,您必須“執行”代碼,偽造堆棧過程,然后才能發現包含將要執行的方法的實例。

可以優化相同的代碼,請參見下面的代碼:

.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

我不知道您想怎么做,但是您擁有解決方案,csprojs和c#類文件,並且您想閱讀代碼,我建議您使用Roslyn來做到這一點。

暫無
暫無

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

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