我可以使用反射来检查方法中的代码吗?

时间:2010-04-22 19:35:39

标签: c# reflection

我正在玩C#反射API。我可以轻松地在程序集中加载类,方法等的Type信息,但是,现在我想知道如何加载和读取方法中的代码?

7 个答案:

答案 0 :(得分:33)

基本答案:

您不能使用反射API(System.Reflection)。

原因是反射api设计用于元数据(类的类型,名称和方法签名,......),但不适用于数据级别(IL-stream本身)。

扩展答案:

您可以使用System.Reflection.Emit(例如ILGenerator Class)发出(但不读取)IL。

通过MethodInfo.GetMethodBody(),您可以获得用于实现方法的二进制IL流。但这本身通常完全没用。

您可以使用外部库(如Cecil)来读取/修改/添加/删除方法中的代码。

答案 1 :(得分:16)

这取决于您阅读代码的含义。有4种形式的代码。

1-源代码,例如。原始的C#或VB.NET - 不,你不能用反射来得到这个 2-符号IL代码 - 不,你不能用反射得到这个 3- JITed汇编代码 - 不,你不能用反射来得到这个

4- IL字节,IL编译到的实际字节,你可以得到。

例如,看看MethodBase.GetMethodBody(),你可以得到IL字节,局部变量,异常帧等。 http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getmethodbody.aspx

答案 2 :(得分:9)

有点可以。相关功能是MethodBase.GetMethodBody

这不是最有用的API。您可以获得有关方法内部内容的一些基本信息,并且可以将IL作为字节数组获取。就是这样。

Mono.Cecil库中的API稍微好一点,它会为MethodDefinition类提供自己的MethodBody实现,其中包含实际的Instructions,所以你没有解释原始字节代码。尽管如此,如果你想从反射器中获取C#代码,你将会非常失望。此外,塞西尔没有很好的文件记录。

如果你还想尝试,那么祝你好运。

答案 3 :(得分:2)

如果您不需要实时执行此操作,请查看Reflector。您可以反汇编任何.NET程序集(包括MS核心DLL),并以您选择的语言查看代码。这可以非常教育。

更新有没有人尝试在Reflector上使用Reflector来弄清楚如何做到这一点?

答案 4 :(得分:1)

没有
这是下一版C#的功能。您可以使用CodeDom获取比反射更多的信息,但是您无法查询解析树。

总是单声道,单声道编译器是一个服务,你可以在运行时获得解析树。

更好的问题是你想要的原因?

答案 5 :(得分:1)

是的,必须有办法实现这一点:.NET Reflector工具也是如此。但不能告诉你它是如何在那里完成的。

答案 6 :(得分:0)

我想提供一个示例,说明如何在方法内部探索代码。正如其他人所解释的那样,使用本机.NET Reflection API很难做到这一点。但是,使用Mono.Reflection API,您可以使用GetInstructions()方法以编程方式反汇编代码并在运行时进行检查。

例如,以下代码检查一个方法并计算其内部的调用次数。作为此类代码的用例,假设我是一位老师(我是),并指示我的同学编程给定方法而无需使用任何其他方法,然后在单元测试中使用此代码,我可以验证给定的约束是受到尊重。

public static class MethodInfoUtil
{
    public static int NbOfInnerCalls(this MethodInfo mi)
    {
        return mi.GetInstructions().Count(
            instruction => instruction.OpCode.FlowControl == FlowControl.Call);
    }
}

示例控制台程序:

class Program
{
    static int Add(int a, int b) => a + b;
    static int Doubling(int a) => Add(a, a);
    static int Quadrupling(int a) => Add(Add(a, a), Add(a, a));

    static void Main(string[] args)
    {
        Console.WriteLine("Inner method calls");
        Console.WriteLine("        Add: {0}", ((Func<int, int, int>)Add).Method.NbOfInnerCalls());
        Console.WriteLine("   Doubling: {0}", ((Func<int, int>)Doubling).Method.NbOfInnerCalls());
        Console.WriteLine("Quadrupling: {0}", ((Func<int, int>)Quadrupling).Method.NbOfInnerCalls());
    }
}

// Output:
// Inner method calls
//         Add: 0
//    Doubling: 1
// Quadrupling: 3