如何以编程方式识别使用C#的方法引用的数量

时间:2008-09-19 23:15:18

标签: c# refactoring

我最近继承了需要修剪和清理的C#控制台应用程序。简而言之,该应用程序由一个包含超过110,000行代码的类组成。是的,一个班级超过110,000行。而且,当然,该应用程序是我们业务的核心,运行'全天候更新动态网站上使用的数据。虽然我被告知我的前任是“一个非常优秀的程序员”,但显然他根本没有进入OOP(或版本控制)。

无论如何......在熟悉代码的同时,我发现了许多声明的方法,但从未引用过。看起来好像使用了复制/粘贴来对代码进行版本化,例如说我有一个名为getSomethingImportant()的方法,很可能还有另一个名为getSomethingImortant_July2007()的方法(在大多数情况下,模式是functionName_ [datestamp])。看起来当程序员被要求对getSomethingImportant()进行更改时,他会复制/粘贴然后重命名为getSomethingImortant_Date,对getSomethingImortant_Date进行更改,然后将代码中的任何方法调用更改为新方法名称,将旧方法保留为代码但从未引用过。

我想编写一个简单的控制台应用程序,它可以遍历一个巨大的类,并返回所有方法的列表,其中包含每个方法的引用次数。根据我的估计,有超过1000种方法,所以这样做需要一段时间。

我可以使用.NET框架中的类来检查此代码吗?或者任何其他有用的工具,可以帮助识别声明但从未引用的方法?

(旁边的问题:有没有其他人见过像这样的C#应用​​程序,一个大型的类?它或多或少是一个巨大的程序过程,我知道这是我见过的第一个,至少是这个尺寸。)

10 个答案:

答案 0 :(得分:12)

如果您只需要提取有关课程的一些统计信息,则可以尝试使用NDepend。请注意,此工具在内部依赖Mono.Cecil来检查程序集。

答案 1 :(得分:4)

下载Resharper的免费试用。使用Resharper->搜索 - >在文件中查找用法(Ctrl-Shift-F7)可以突出显示所有用法。此外,状态栏中将显示计数。如果要搜索多个文件,也可以使用Ctrl-Alt-F7。

进行搜索

如果您不喜欢这样,请在Visual Studio中搜索函数名称(Ctrl-Shift-F),这应该告诉您在解决方案中找到了多少次事件,以及它们的位置。

答案 2 :(得分:4)

要完成 Romain Verdier 的答案,让我们深入了解NDepend可以为您带来什么。 (免责声明:我是NDepend团队的开发人员

NDepend允许使用一些LINQ查询来查询.NET代码。知道哪些方法调用和被其他方法调用,就像编写以下LINQ查询一样简单:

from m in Application.Methods
select new { m, m.MethodsCalled, m.MethodsCallingMe }

此查询的结果以便于浏览调用者和被调用者(以及它100%集成到Visual Studio中)的方式呈现。

NDepend methods callers and callees


还有许多其他NDepend功能可以帮助您。例如,您可以右键单击Visual Studio中的方法> NDepend>选择方法...>正在使用我(直接或间接) ......

NDepend Visual Studio method right click

生成以下代码查询...

from m in Methods 
let depth0 = m.DepthOfIsUsing("NUnit.Framework.Constraints.ConstraintExpression.Property(String)")
where depth0  >= 0 orderby depth0
select new { m, depth0 }

...匹配直接和间接呼叫者,呼叫深度(1表示直接呼叫者,2表示直接呼叫者的呼叫者,依此类推)。

NDepend indirect method callers

然后点击按钮导出到图表,您将获得您的枢轴方法的调用图(当然它可能是相反的方式,即直接或间接由特定枢轴调用的方法法)。

NDepend call graph

答案 3 :(得分:1)

我认为你不想自己写这个 - 只需购买NDepend并使用Code Query Language

答案 4 :(得分:1)

Reflector中的分析器窗口可以显示调用方法的位置(使用者) 听起来好像需要很长时间来获取信息 您可以查看Reflector为编写加载项提供的API,看看您是否可以通过这种方式获得分析的繁琐工作。我希望code metrics add-in的源代码可以告诉你如何从反射器API获取有关方法的信息。

编辑:Reflector的code model viewer加载项也可以提供帮助。这是探索Reflector API的好方法。

答案 5 :(得分:1)

FXCop有一条规则可以识别未使用的私有方法。因此,您可以将所有方法标记为私有,并让它生成列表。

如果你想获得更高级的话,FXCop也有一种语言 http://www.binarycoder.net/fxcop/

答案 6 :(得分:1)

如果你不想为NDepend外壳,因为它听起来像一个程序集中只有一个类 - 注释掉方法并编译。如果它编译,删除它们 - 你不会有任何继承问题,虚拟方法或类似的东西。我知道这听起来很原始,但有时重构只是像这样的笨拙的工作。这是假设您在每次构建之后运行的单元测试,直到您清除了代码(红色/绿色/重构)。

答案 7 :(得分:0)

我不知道为处理这种特殊情况而构建的任何东西,但你可以使用Mono.Cecil。反映程序集,然后计算IL中的引用。不应该太强硬。

答案 8 :(得分:0)

在.NET框架本身中没有简单的工具可以做到这一点。但是我不认为你真的需要一次未使用的方法列表。在我看来,你只需要查看代码,然后为每个方法检查它是否未使用,然后删除它。我使用Visual Studio“查找引用”命令来执行此操作。或者,您可以使用Resharper及其“Analize”窗口。或者您可以使用Visual Studio代码分析工具查找所有未使用的私有方法。

答案 9 :(得分:-1)

尝试让编译器发出汇编程序文件,如x86指令,而不是.NET程序集。

为什么呢?因为解析汇编代码要比C#代码或.NET程序集容易得多。

例如,函数/方法声明如下所示:

    .string "w+"
    .text
    .type   create_secure_tmpfile, @function
create_secure_tmpfile:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $-1, -8(%ebp)
    subl    $4, %esp

和函数/方法引用将如下所示:

    subl    $12, %esp
    pushl   24(%ebp)
    call    create_secure_tmpfile
    addl    $16, %esp
    movl    20(%ebp), %edx
    movl    %eax, (%edx)

当您看到“create_secure_tmpfile:”时,您知道您有一个函数/方法声明,当您看到“call create_secure_tmpfile”时,您知道您有一个函数/方法引用。这对你的目的来说可能已经足够了,但如果没有,那么在你为整个应用程序生成一个非常可爱的调用树之前,还需要几个步骤。