我最近继承了需要修剪和清理的C#控制台应用程序。简而言之,该应用程序由一个包含超过110,000行代码的类组成。是的,一个班级超过110,000行。而且,当然,该应用程序是我们业务的核心,运行'全天候更新动态网站上使用的数据。虽然我被告知我的前任是“一个非常优秀的程序员”,但显然他根本没有进入OOP(或版本控制)。
无论如何......在熟悉代码的同时,我发现了许多声明的方法,但从未引用过。看起来好像使用了复制/粘贴来对代码进行版本化,例如说我有一个名为getSomethingImportant()的方法,很可能还有另一个名为getSomethingImortant_July2007()的方法(在大多数情况下,模式是functionName_ [datestamp])。看起来当程序员被要求对getSomethingImportant()进行更改时,他会复制/粘贴然后重命名为getSomethingImortant_Date,对getSomethingImortant_Date进行更改,然后将代码中的任何方法调用更改为新方法名称,将旧方法保留为代码但从未引用过。
我想编写一个简单的控制台应用程序,它可以遍历一个巨大的类,并返回所有方法的列表,其中包含每个方法的引用次数。根据我的估计,有超过1000种方法,所以这样做需要一段时间。
我可以使用.NET框架中的类来检查此代码吗?或者任何其他有用的工具,可以帮助识别声明但从未引用的方法?
(旁边的问题:有没有其他人见过像这样的C#应用程序,一个大型的类?它或多或少是一个巨大的程序过程,我知道这是我见过的第一个,至少是这个尺寸。)
答案 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功能可以帮助您。例如,您可以右键单击Visual Studio中的方法> NDepend>选择方法...>正在使用我(直接或间接) ......
生成以下代码查询...
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表示直接呼叫者的呼叫者,依此类推)。
然后点击按钮导出到图表,您将获得您的枢轴方法的调用图(当然它可能是相反的方式,即直接或间接由特定枢轴调用的方法法)。
答案 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”时,您知道您有一个函数/方法引用。这对你的目的来说可能已经足够了,但如果没有,那么在你为整个应用程序生成一个非常可爱的调用树之前,还需要几个步骤。