我正在使用Cecil检查我的程序。除了一个例外,它的工作非常好。如何使用Cecil查找抽象方法的实现?
这是一个代码示例,其中 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();
}
}
当我使用下面的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();
如何让我的Cecil代码找到实现方法 ImplementingType :: MyMethod()?
答案 0 :(得分:2)
来自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一样工作,使用堆栈。
您的堆栈将包含1个项目,即ImplementingType
的实例
您的筹码将有0个项目,而ImplementingType的实例将保存在第一个变量
中
您的堆栈将再次有1个项目,即ImplementingType
的实例
从堆栈中的第一项调用MyMethod,即ImplementingType的实例。
因此无法仅使用行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来做到这一点。