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

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

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

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

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

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

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

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

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

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

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

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

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

NDepend方法调用者和被调用者


还有许多其他NDependfunction可以帮助您。 例如,您可以右键单击Visual Studio> NDepend> Select methods …>中使用我的方法(直接或间接)

NDepend Visual Studio方法右键单击

生成以下代码查询…

 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间接方法调用者

然后通过单击“ 导出到图形 ”按钮,您将获得您的pivot方法的调用图(当然,它可能是相反的方式,即通过特定的pivot方法直接或间接调用的方法)。

NDepend调用图

我不认为你想自己写这个 – 只需购买NDepend并使用它的代码查询语言

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

FXCop也有一种语言,如果你想获得更多的发烧友http://www.binarycoder.net/fxcop/

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

Reflector中的Analyzer窗口可以显示调用方法的位置(Used By)。
听起来好像需要很长时间来获取信息。
您可以查看Reflector为编写加载项提供的API,看看您是否可以通过这种方式获得分析的繁重工作。 我希望代码度量标准加载项的源代码可以告诉您如何从reflection器API获取有关方法的信息。

编辑:Reflector的代码模型查看器加载项也可以提供帮助。 这是探索Reflector API的好方法。

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

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

尝试使编译器发出汇编程序文件,如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”时,您知道您有一个函数/方法引用。 这对你的目的来说可能已经足够了,但如果没有,那么在你为整个应用程序生成一个非常可爱的调用树之前,还需要几个步骤。