【问题标题】:How to determine which methods are called in a method?如何判断一个方法中调用了哪些方法?
【发布时间】:2011-05-03 16:42:11
【问题描述】:

我想列出从特定方法调用的所有方法。例如。如果我有以下代码:

public void test1() {

   test2();


   test3();
}

该列表应包含 test2() 和 test3()。如果可以列出同一类的方法,也可以列出另一个类的方法,那就太好了。

另外我想找到一种方法来检测方法中使用了哪些字段:

public class A {

   private String test1 = "";
   private String test2 = "";

   public void test() {
      Console.WriteLine(test1);
   }

}

因此应该列出 test1。

我使用 Mono.Cecil 进行了尝试,但不幸的是,我找不到有关该项目的大量文档。那么有人知道怎么做吗?

编辑:我想用 Mono.Cecil 来做,因为通过它的 API,我可以直接在我的应用程序中使用结果。如果我使用 Visual Studio 或类似工具中的内置工具,则很难进一步处理结果。

【问题讨论】:

    标签: c# .net mono.cecil


    【解决方案1】:

    我并没有真正与 Cecil 合作过,但 HowTo 页面显示了如何枚举类型,您的问题似乎只需要循环遍历您之后的指令:调用和加载字段。此示例代码似乎可以处理您提到的情况,但可能还有更多,您可能也应该检查其他调用说明。如果你让它递归,请确保你跟踪你已经检查过的方法。

    static void Main(string[] args)
    {
        var module = ModuleDefinition.ReadModule("CecilTest.exe");
    
        var type = module.Types.First(x => x.Name == "A");
        var method = type.Methods.First(x => x.Name == "test");
    
        PrintMethods(method);
        PrintFields(method);
    
        Console.ReadLine();
    }
    
    public static void PrintMethods(MethodDefinition method)
    {
        Console.WriteLine(method.Name);
        foreach (var instruction in method.Body.Instructions)
        {
            if (instruction.OpCode == OpCodes.Call)
            {
                MethodReference methodCall = instruction.Operand as MethodReference;
                if(methodCall != null)
                    Console.WriteLine("\t" + methodCall.Name);
            }
        }
    }
    
    
    public static void PrintFields(MethodDefinition method)
    {
        Console.WriteLine(method.Name);
        foreach (var instruction in method.Body.Instructions)
        {
            if (instruction.OpCode == OpCodes.Ldfld)
            {
                FieldReference field = instruction.Operand as FieldReference;
                if (field != null)
                    Console.WriteLine("\t" + field.Name);
            }
        }
    }
    

    【讨论】:

    • 非常感谢。我昨天已经尝试过类似的方法,但我的问题是 ModuleDefinition.ReadModule("test.dll");不起作用。总是出现ModuleDefinition不包含方法ReadModule(String)的错误
    • @Roflcoptr 那么您根本没有使用正确版本的 Cecil。从github.com/jbevain/cecil 获取它,Kris 发布的代码将起作用。
    • @Mario:我想是的,但是今天和明天我没有时间检查这个旧项目......
    【解决方案2】:

    这不能简单地使用 C# 中的反射 API 来完成。确实,您需要解析原始源代码,这可能不是您正在寻找的解决方案。但例如这就是 Visual Studio 获取此类信息进行重构的方式。

    您可能会在某个地方分析 IL - 按照 Reflector 所做的工作,但我认为这将是一项巨大的工作。

    【讨论】:

    • 是的,我已经用反射 API 试过了,但没那么容易。所以我尝试使用 Mono.Cecil,因为我想在我的代码中使用计算结果。 (见我的编辑)
    • 啊!我不熟悉 Mono.Cecil - 但它看起来很有趣。如果你准备好用 IL 弄脏你的手,那么这应该是可能的 - 但抱歉我无能为力 - 祝你好运。
    【解决方案3】:

    如果您想付款,可以使用.NET Reflector tool。你也可以看看这个.NET Method Dependencies,不过它会变得很棘手,因为你将要进入 IL。第三种可能是在 VS 中使用宏引擎,它确实具有分析代码的功能,CodeElement,但我不确定它是否可以做依赖。

    【讨论】:

    • 我想使用农场/图书馆,因为我想直接在我的应用程序中使用计算结果。 (见我的编辑)
    • 编辑:啊,我现在明白了,Reflector 工具也有一个 API,这看起来非常棒。我认为它应该能够解决至少部分问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多