65.9K
CodeProject 正在变化。 阅读更多。
Home

使用NDepend简化代码

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (25投票s)

2009 年 11 月 3 日

CPOL

8分钟阅读

viewsIcon

284350

通过本文,您将了解如何使用 NDepend 来控制/分析您的应用程序。它允许应用设计规则并重构代码。

目录

引言

在当今世界,当您开发一个拥有庞大代码库的实际应用程序时,我们必须考虑许多属性。其中一些是可维护性、可理解性、清晰度、依赖性、产品优越性等。我们投入大量精力维护代码,使代码注释良好,以便未来的开发人员更好地理解代码,我们发现两个或多个程序集之间的依赖关系并尝试最小化依赖关系,限制代码行数等等,最后在发布产品以供将来使用之前进行测试。

在此过程中,我们浪费了大量时间,这些时间本可以用于开发更好的代码。

如果一切都无需思考就能完成呢?是的,NDepend [^] 允许您处理大型项目,随时获取所有内容的摘要。因此,无论程序集有多大,程序集中有多少类型,项目中有多少行代码,您都可以轻松确定代码质量以及应该检查和重构的代码部分。

背景

Patrick Smacchia,一位 C# MVP,于 2007 年推出了 NDepend。NDepend 的主要动机是让架构师清楚地了解对象之间的交叉依赖关系、它们之间的关联级别以及轻松发现代码状况。我将讨论我们如何使用 NDepend 在我们的应用程序中轻松管理代码。

依赖循环

我们中的许多人会同意,避免组件之间的依赖循环是良好软件设计的基本原则。如果组件 A 依赖于 B,B 依赖于 C,而 C 又依赖于 A,则组件 A 无法在没有 B 和 C 的情况下独立测试或开发。因此,A、B 和 C 形成一个不可分割的单元。在代码可维护性方面,这个不可分割的单元的成本高于单个单元。建议维护 1,000 行代码的成本可能比维护两个 500 行独立代码块所需的工作量多三到四倍。因此,对于任何合理的架构,都接受每个组件为 500 - 1,000 行代码,并且这些组件之间没有依赖循环。

依赖结构矩阵

依赖结构矩阵用于了解一个命名空间对另一个命名空间的依赖程度。控制台可帮助您了解一个类与另一个类之间的依赖关系。让我们看看下面的图片

clip_image002.gif

蓝色单元格表示 x 和 y 轴上两个命名空间之间的依赖关系。例如,左下角的单元格 (0,12) 表示命名空间 Spring.Proxy 通过最短路径长度为五间接使用命名空间 Spring.Threading。最短路径是指这些项不直接依赖,而是依赖于反过来又依赖于另一个并最终依赖于它的程序集。
黑色单元格表示两个命名空间之间存在依赖循环。例如,单元格 [9,7] 和 [7,9] 显示命名空间 Spring.Validation 和 Spring.Core.* 属于最短长度为五的依赖循环。

黑色单元格周围的红色框表示每个组件都直接或间接相互依赖,因此创建了一个无法独立运行的超级组件。
您可以重构代码结构以消除代码之间的依赖关系。您可以从此处 [^] 阅读更多关于依赖循环的信息。

代码查询语言

NDepend 提供给我们的另一个有用且独特的功能是 CQL。它允许在 .NET 对象上编写查询。这对于处理大量代码库确实很有帮助。我们可以使用简单的 SQL 样式的查询来找到我们想要的需求。例如,假设我们想获取所有行数超过 200 的方法(为了更好的代码结构,单个方法中的行数应始终少于 200)。我们可以使用简单的查询,例如

 SELECT METHODS OUT OF
 NAMESPACES "MyApp.MyNamespace1","MyApp.MyNamespace2"
 WHERE NbILInstructions > 200 
 ORDER BY NbILInstructions DESC

因此,它将在 MyNamespace1MyNamespace2 中搜索,并尝试查找行数超过 200 的方法,并在控制台中按行数顺序列出。
如果我们要获取实现 IDisposable 的类型,我们编写

SELECT TYPES WHERE IsClass AND Implements "System.IDisposable"
此外,CQL 支持内置功能,可将规则纳入您的 .NET 应用程序。

NDepend 的实际示例

在所有这些初步讨论之后,现在是获取一些关于如何使用 NDepend 的实践知识的时候了。我将根据需要讨论 NDepend 控制台中提供的其他 UI 元素。

1. 比较相同程序集的构建

NDepend 的独特功能是提供对两次构建之间所做所有更改的快速概述。NDepend 提供了一个出色的 UI 来比较两次构建。我们可以轻松使用 CQL 来查看哪些方法已更改、哪些已删除、哪些已修改等等。让我们给出一个快速示例

Compare1.JPG

在上图中,您可以看到如何开始比较程序集之间的构建。

  • 启动 Visual NDepend。选择代码库的 2 个版本
  • 在出现的对话框中,选择要比较的 2 个程序集。您也可以选择一个或多个具有相互依赖关系的程序集。然后单击确定
  • 在初始构建过程之后,它将打开比较控制台,如下图所示。

    Compare2.JPG

  • 在图中您可以看到 4 个部分
    1. 类浏览器:在此部分中,控制台显示类结构层次结构,以确定程序集中哪些已更改。如您所见,它清楚地划分了每个命名空间。划掉的命名空间表示存在于旧版本中,但在新版本中已删除;下划线表示在新版本中已修改,粗体节点是新添加的。
      因此,从这棵树中我们可以清楚地了解两个版本之间发生了什么变化。
    2. 度量:它表示在两个程序集中定义的所有方法的度量。如果将鼠标悬停在此部分的任何位置,它会显示行数和方法的名称,如上图所示。
    3. 信息:此部分显示当前选定项的摘要,例如IL 指令数、注释行数、行数、圈复杂度等
    4. CQL 查询部分此部分允许您定义自定义 CQL 查询来过滤输出。您可以定义 CQL,例如
      SELECT NAMESPACES FROM ASSEMBLIES "XXXX.AssetTracker.Data" 
      WHERE NbLinesOfCode > 100
      它将列出程序集 XXXX.AssetTracker.Data 下所有代码行数超过 100 的命名空间。

    这 4 个部分可用于获取有关两次程序集之间所做所有更改的全部知识。

compare3.JPG

除了自己输入查询,您还可以通过右键单击命名空间并选择“什么发生了变化?”来找到最合适的查询,如上图所示。类型将为您列在 CQL 查询结果中。

分析我们的代码

比较代码库后,让我们分析我们的代码。要分析,请从 Visual Ndepend 控制台的初始屏幕中选择“分析一组 .NET 程序集”

analyze1.JPG

从出现的对话框中,选择要分析的 dll,然后单击“确定”。该过程将构建程序集,分析它并生成报告。如果您查看报告,您可以清楚地了解这些 dll 中做了什么、依赖矩阵等。

要进一步检查,请看下图

analyze2.JPG

SELECT TYPES FROM ASSEMBLIES "XXX.Framework" WHERE IsPublic

这里 CQL 返回了程序集中所有公共命名空间的输出。列表显示有 60 种此类类型,每种类型都定义了其中的行数。下面的面板给出了搜索统计分析。

在代码中添加约束

除了所有这些功能之外,NDepend 还允许您与 Visual Studio 集成。从控制台单击“安装”以打开此窗口

Code1.JPG

该对话框将 NDepend 插件安装到 Visual Studio。它还允许您将 Reflector 安装到 Visual Studio。对话框中出现的按钮将有助于完成此操作。

现在,从您的 Visual Studio IDE,我们可以访问 CQL 查询并轻松检查依赖矩阵。随时右键单击代码,您会找到 NDepend 上下文菜单选项。

code2.JPG

因此,我们也可以直接从代码轻松访问 CQL 查询。这提供了在编写代码时更好地掌握代码的额外好处。NDepend 还允许您直接在代码中编写约束。它通常使用 XML 文件来存储此约束。如果您将 NDepend.CQL.dll 添加到您的项目中,您可能会添加

[NDepend.CQL.CQLConstraint("WARN IF Count>0 SELECT METHODS WHERE NbLinesOfCode > 400")]
以在代码编译时没有遵循约束时直接警告我。

下载此工具

要下载此工具,请点击此链接。 [^]

供进一步阅读

代码查询语言 [^]
提示和技巧 [^]
度量定义 [^]

结论

首先,我必须感谢 Patrick,让我尝试这个并授予我撰写他开发的这个伟大工具的荣誉。这里有很多对我来说很新的术语,都是在学习过程中学到的。所以如果我犯了任何错误,请告诉我,以便我更新文章。

历史

初始构建:2009 年 11 月 4 日。
这是 NDepend 的初步介绍。欢迎评论。

© . All rights reserved.