6

我最近继承了需要修剪和清理的 C# 控制台应用程序。长话短说,该应用程序由一个包含超过 110,000 行代码的类组成。是的,一个类中超过 110,000 行。当然,该应用程序是我们业务的核心,它全天候运行更新动态网站上使用的数据。尽管有人告诉我我的前任是“一个非常优秀的程序员”,但很明显他根本不喜欢 OOP(或版本控制)。

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

我想编写一个简单的控制台应用程序,它爬过一个巨大的类并返回所有方法的列表以及每个方法被引用的次数。据我估计,有超过 1000 种方法,所以手工完成需要一段时间。

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

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

4

10 回答 10

13

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

于 2008-09-19T23:22:35.590 回答
6

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

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

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

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

NDepend 方法调用者和被调用者


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

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

然后通过单击按钮Export to Graph,您将获得枢轴方法的调用图(当然也可以反过来,即由特定枢轴方法直接或间接调用的方法)。

NDepend 调用图

于 2008-10-26T17:29:30.923 回答
4

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

如果您不喜欢这样,请在 Visual Studio (Ctrl-Shift-F) 中对函数名称进行文本搜索,这应该会告诉您在解决方案中找到了多少次,以及它们在哪里。

于 2008-09-19T23:42:44.793 回答
1

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

于 2008-09-19T23:23:16.557 回答
1

Reflector中的 Analyzer 窗口可以显示调用方法的位置(Used By)。
听起来要花很长时间才能以这种方式获取信息。
您可能会查看 Reflector 提供的用于编写插件的 API,看看您是否可以通过这种方式完成繁重的分析工作。我希望代码度量加载项的源代码可以告诉您一些有关如何从反射器 API 获取有关方法的信息的信息。

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

于 2008-09-19T23:28:28.667 回答
1

.NET 框架本身没有简单的工具可以做到这一点。但是我不认为你真的需要一次未使用的方法列表。正如我所看到的,您只需浏览代码,对于每种方法,您将检查它是否未使用,如果是,则将其删除。我会使用 Visual Studio“查找引用”命令来做到这一点。或者,您可以使用带有“分析”窗口的 Resharper。或者您可以只使用 Visual Studio 代码分析工具来查找所有未使用的私有方法。

于 2008-09-19T23:29:50.097 回答
1

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

如果你想变得更漂亮,FXCop 也有一种语言 http://www.binarycoder.net/fxcop/

于 2008-09-20T00:56:48.983 回答
1

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

于 2008-09-22T22:01:16.477 回答
0

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

于 2008-09-19T23:17:38.347 回答
-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”时,您知道您有一个函数/方法引用。这对于您的目的可能已经足够了,但如果不是这样,您只需再执行几个步骤,就可以为整个应用程序生成一个非常可爱的调用树。

于 2008-09-20T00:17:24.757 回答