在依赖项关系图上映射代码间的依赖关系

如果你想了解代码中的依赖关系,可使用 Visual Studio Ultimate 将它们映射出来。 想要了解所有代码之间的依赖关系时,可通过创建代码图使其可视化(仅 Visual Studio Ultimate)。 这样有助于你查看代码如何相互配合,而无需读取文件和各行代码。

具有选定项和展开组的关系图

以下是一些相关视频:

你将需要以下项目:

  • Visual Studio Ultimate 2013

  • 解决方案或程序集(.dll 或 .exe)中的 Visual C# .NET 或 Visual Basic .NET 代码

  • Visual C++ 项目、头文件(.h 或 #include)或二进制文件中的本机或托管的 C 或 C++ 代码

  • 通过 Visual Studio 2013 Update 3 来映射以下内容中的依赖关系:

    • 跨多个应用共享代码的项目

    • 通过 Microsoft Dynamics AX 的 .NET 模块生成的 X++ 项目和程序集

    你还可以把程序集和二进制文件从 Windows 资源管理器中拖到一个现有的关系图中并获取颜色代码关系。

从这里开始:

  • 若要查看整个解决方案中的整体依赖关系,请转到“体系结构”菜单。 依次单击“生成依赖项关系图”、“针对解决方案”。

    - 或 -

  • 若要查看解决方案中的特定的依赖关系,请打开“解决方案资源管理器”。 选择你感兴趣的项目、程序集引用、文件夹、文件、类型或成员。 在“解决方案资源管理器”工具栏上,单击“创建新的关系图文档”“从选定节点创建新的关系图”按钮

你还可以:

  • 了解 C 或 C++ 源文件和头文件之间的依赖关系

  • 共享依赖项关系图

  • 以编程方式创建关系图

查看整体依赖关系

查看解决方案中的依赖关系

  1. 在“体系结构”菜单上,依次单击“生成依赖关系图”、“针对解决方案”。

    你将获得显示顶级程序集和这些程序集之间的聚合链接的关系图。 聚合链路越广,它所代表的依赖关系就越多。 **“外部”**组包含你的解决方案之外的任何内容,包括平台依赖项。 外部程序集仅显示已使用的项。

    程序集的顶级依赖项关系图

  2. 若要查看程序集内部,请展开程序集。 将鼠标指针移动到程序集的顶部,然后单击出现的 V 型 (“^”)。 (键盘:选择项,然后按“加号”,即键 (+)。)若要查看更深层次的代码,请对命名空间、类型和成员执行相同操作。

    带有分组节点的依赖项图

    默认情况下,包含关系以组的形式显示,你可以对其进行展开和折叠。 若要了解作为链接的组关系,请在关系图快捷菜单上,依次单击“组”、“关闭分组”。

    带有节点和链接的依赖项图

  3. 若要检查聚合链接表示的项和依赖项,请首先选择该链接,然后打开它的快捷菜单。 依次单击“显示”、“当前关系图中的参与链接”或“新关系图中的参与链接”。

    Visual Studio 将展开位于链接两端的组,且仅显示参与链接的项和依赖项。

  4. 若要获取有关项或链接的详细信息,请将指针移至项的顶部,直至出现工具提示。 这显示的是链接所代表的类别。

  5. 若要了解链接颜色意味着什么,请在图工具栏上单击“图例”。

    如果你看到的是绿色链接,它是指可能不仅仅存在继承关系。 可能也存在方法调用,但是这些都被继承关系所隐藏。

  6. 若要了解组间成员间的依赖关系,请单击关系图上的一个项。

    具有选定项和展开组的关系图

  7. 若要发现代码中的潜在问题,请运行分析器

请参阅:

查看程序集间或二进制文件间的依赖关系

  • 创建空白关系图,或打开现有关系图(.dgml 文件)。 从 Visual Studio 外部,将程序集或二进制文件拖至关系图。

    备注

    仅当在相同的用户访问控制 (UAC) 权限级别运行 Windows 资源管理器和 Visual Studio 时,才能从 Windows 资源管理器拖动程序集或二进制文件。例如,如果启用了 UAC,并且你正以管理员身份运行 Visual Studio,则 Windows 资源管理器将阻止拖动操作。若要解决此问题,请确保 Visual Studio 以管理员身份运行,或者关闭 UAC。请注意,在 Windows 8 中,Windows 资源管理器即为文件资源管理器。

创建一个空白关系图

  1. 在“解决方案资源管理器”中,打开顶级解决方案节点的快捷菜单。 依次单击“添加”、“新项”。

  2. 在“已安装”下,单击“常规”。

  3. 在右窗格中,单击“定向关系图文档”。

    解决方案的“解决方案项”文件夹中出现空白关系图。

    若要打开一个新的空白关系图而不将其添加到解决方案中,请在“文件”菜单中,依次单击“新建”、“文件”。

    若要向建模项目中添加一个空白关系图,请打开“体系结构”菜单,单击“新建关系图”。

问题解答

问:为什么创建关系图需要这么长时间?

**答:**在首次生成关系图时,Visual Studio 会将其找到的所有依赖关系都编入索引中。 这个过程可能需要一些时间,尤其是针对大型解决方案,但是这样会提高之后的性能。 如果更改了代码,Visual Studio 只会将已更新的代码重新编入索引。 如果你不想等到关系图创建完成,可以随时取消步骤并尝试执行以下操作:

  • 仅列出你感兴趣的依赖项的关系图。

  • 在生成整个解决方案的关系图之前,缩小解决方案范围。

尽管 Visual Studio 可在 1 GB 内存下运行,但我们建议你的计算机至少具有 2 GB 内存,以避免在 Visual Studio 创建代码索引并生成关系图时产生长时间的延迟。

当项目项的“复制到输出目录”属性设置为“始终复制”时,通过解决方案资源管理器创建关系图或将项添加到关系图可能需要更多时间。 这可能导致增量生成问题,并且 Visual Studio 每次都重新生成项目。 若要提高性能,请将此属性更改为“如果较新则复制”或 PreserveNewest。 请参阅增量生成

问:为什么 Visual Studio 没有创建我的关系图?

**答:**当你的解决方案中未成功生成任何项目时,可能发生该情况。 如果至少有一个项目成功生成,则 Visual Studio 将生成关系图。 关系图只会为成功创建的代码显示依赖关系。 如果某些组件出现生成错误,则这些错误会出现在关系图上。 在基于关系图做出体系结构决策时,请确保组件实际生成并且具有依赖项。

查看特定依赖关系

例如,假设你在一些具有挂起更改的文件中执行代码审阅。 若要查看这些更改中的依赖关系,请从这些文件中创建一个依赖项关系图。

带有分组节点的依赖项图

查看解决方案中特定的依赖关系

  1. 打开“解决方案资源管理器”。 选择你感兴趣的项目、程序集引用、文件夹、文件、类型和成员。

  2. 将项和它们的成员编入关系图。 在“解决方案资源管理器”工具栏上,单击“创建新的关系图文档”“从选定节点创建新的关系图”按钮

    若要找出与类型或成员有依赖关系的项,请从“解决方案资源管理器”中打开类型或成员的快捷菜单。 单击依赖关系类型。 然后选择结果。

    如何可视化特定代码

    若要让项具有复合层次结构,请在“解决方案资源管理器”工具栏上,打开“创建新的关系图文档...”列表。 单击“新建包含上级的依赖项关系图”。

    如何可视化特定代码和父代码

    你也可以把项拖到一个空白关系图或现存关系图中。 如要创建空白关系图,请在“文件”菜单上,依次单击“新建”、“文件”、“定向关系图文档”。 若要包含你的项的父层次结构,请在拖动项时按住 Ctrl 键。

    备注

    当你从在多个应用程序(如 Windows Phone 或 Windows 应用商店)之间共享的项目添加项时,这些项将与当前活动的应用程序项目一起显示在代码图上。如果你将上下文更改为另一个应用程序项目并从共享的项目添加更多项,则这些项现在将与最近活动的应用程序项目一起显示。你对代码图上的项执行的操作仅适用于共享相同上下文的项。

  3. 如要查看项,请把项展开。 将鼠标指针移动到程序集的顶部,然后单击出现的 V 型 (“^”) 按钮。 若要展开所有项,请打开关系图的快捷菜单。 依次单击“组”、“展开所有”。

    备注

    如果展开所有组会生成不可用的关系图或产生内存问题,则该选项不可用。

  4. 若要查看代码中存在而关系图上不显示的成员,请单击“重新提取子级”“重新提取子级”图标。 这些组成员以不同的类型显示,以便你可以更容易地查看。 请参阅编辑和自定义依赖项关系图

  5. 如要查看关系图上与这些相关的更多项,请打开该项的快捷菜单。 单击“显示”以及你所感兴趣的关系类型。

    针对程序集,则单击:

    引用的程序集

    添加此程序集引用的程序集。 外部程序集将显示在“外部”组中。

    引用程序集

    在解决方案中添加引用此程序集的程序集。

    针对类,则单击:

    基类型

    对于类,添加基类和实现的接口。

    对于接口,请添加基接口。

    派生类型

    对于类,添加派生类。

    对于接口,请添加派生接口和实现类或结构。

    所有基类型

    以递归方式添加基类或接口层次结构。

    所有派生类型

    对于类,以递归方式添加所有派生类。

    对于接口,请以递归方式添加所有派生接口和实现类或结构。

    包含层次结构

    添加父容器的层次结构。

    使用的类型

    添加此类使用的所有类及其成员。

    使用者类型

    添加使用此类的所有类及其成员。

    针对方法,则单击:

    包含层次结构

    添加父容器的层次结构。

    所调用的方法

    添加此方法调用的方法。

    调用者方法

    添加调用此方法的方法。

    基类型中已重写的方法

    对于重写其他方法或者实现接口方法的方法,在已重写的基类和已实现的接口方法(如果有)中添加所有抽象方法或虚方法。

    引用的字段

    添加此方法引用的字段。

    针对字段,则单击:

    包含层次结构

    添加父容器的层次结构。

    引用方法

    添加引用此字段的方法。

查看程序集间或二进制文件中的依赖关系

  1. 在“体系结构”菜单上,依次单击“Windows”、“体系结构资源管理器”。

  2. 在第一列中的**“文件系统”下,单击“选择文件”**。

  3. 在**“打开”**框中,查找并选择程序集或二进制文件。 单击“打开”将它们添加到“体系结构资源管理器”下一列中。

  4. 在下一列中,选择程序集或二进制文件。

    默认情况下,下一列将显示选定项所包含的项。

    提示

    若要选择其他相关项,请将折叠的列展开到包含所选内容的列右侧。在“节点导航”下,选择你感兴趣的项类型。在“出站导航”“入站导航”下,选择你感兴趣的关系类型。请参阅使用体系结构资源管理器查找代码

  5. 查找并选择想要放在关系图上的所有项。

  6. 若要创建新的关系图,请在“体系结构资源管理器”工具栏上,单击“从所有选定节点创建新的关系图文档”“从选定节点创建新的关系图”按钮

    - 或 -

    若要将你的选择添加到关系图,则按下列步骤执行:

    1. 打开关系图的 .dgml 文件,或创建空白关系图。

    2. 在“体系结构”工具栏上,单击“将所选的全部节点添加到当前可见的关系图文档”“将所有选定节点添加到关系图”按钮

      - 或 -

      将项从**“体系结构资源管理器”**拖至关系图。

了解 C 和 C++ 源文件和头文件之间的依赖关系

如果你想创建更多 C++ 项目的关系图,请在这些项目上设置浏览信息编译器选项 (/FR)。 请参阅/FR、/Fr(创建 .Sbr 文件)。 否则,将出现一条消息并提示你设置此选项。 如果你选择“确定”,就只会为当前关系图设置选项。 你可以选择隐藏所有后来关系图的信息。 如果你隐藏了该信息,则可以让它再显示。 将以下注册表项设置为 0 或删除该项:

HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0\NativeProvider : AutoEnableSbr

打开包含 Visual C++ 项目的解决方案时,可能需要花一些时间来更新 IntelliSense 数据库。 在此期间,你可能无法为标头(.h 或 #include)文件创建依赖项关系图,直到 IntelliSense 数据库完成更新。 你可在 Visual Studio 状态栏中监视更新进度。 若要解决因某些 IntelliSense 设置被禁用而导致的问题或消息,请查看针对 C 和 C++ 代码的故障排除图。

  • 若要查看解决方案中所有源文件和头文件间的依赖关系,请在“体系结构”菜单上,依次单击“生成依赖项关系图”、“针对包括文件”。

    本机代码的依赖项关系图

  • 若要查看当前打开文件和相关的源文件以及头文件之间的依赖关系,请打开相关的源文件或头文件。 在文件内的任何地方打开文件快捷菜单。 单击“生成包含文件关系图”。

    .h 文件的第一级依赖项关系图

针对 C 和 C++ 代码的故障排除图

C 和 C++ 代码不支持这些项:

  • 基类型不会显示在包含父层次结构的关系图中。

  • 大多数**“显示”**菜单项不适用于 C 和 C++ 代码。

你在为 C 和 C++ 代码创建依赖项关系图时可能会出现这些问题:

问题

可能的原因

解决方法

依赖项关系图无法生成。

解决方案中没有项目成功生成过。

修复出现的生成错误,然后重新生成关系图。

当你尝试从“体系结构”菜单中生成依赖项关系图时,Visual Studio 无响应。

程序数据库 (.pdb) 文件可能已损坏。

.pdb 文件将存储调试信息,例如,类型、方法和源文件信息。

重新生成解决方案,然后重试。

禁用 IntelliSense 浏览器数据库的某些设置。

Visual Studio 的“选项”对话框中可能已禁用某些 IntelliSense 设置。

打开设置以启用它们。

请参阅选项,文本编辑器,C/C++,高级

消息“未知方法”将出现在方法节点上。

由于无法解析方法的名称,导致出现此问题。

二进制文件可能没有基重定位表。

在链接器中打开 /FIXED:NO 选项。

请参阅/FIXED(固定基址)

无法生成程序数据库 (.pdb) 文件。

.pdb 文件将存储调试信息,例如,类型、方法和源文件信息。

在链接器中打开 /DEBUG 选项。

请参阅/DEBUG(生成调试信息)

无法在预期位置打开或找到 .pdb 文件。

确保 .pdb 文件位于预期位置。

已从 .pdb 文件中去除调试信息。

如果链接器中已使用 /PDBSTRIPED 选项,则改为包含完整的 .pdb 文件。

请参阅/PDBSTRIPPED(去除私有符号)

调用方不是函数,它是二进制文件中的形式转换 (thunk) 或数据节中的指针。

当调用方是形式转换 (thunk) 时,尝试使用 _declspec(dllimport) 以避免形式转换 (thunk)。

请参阅:

共享依赖项关系图

与其他 Visual Studio 用户共享关系图

  • 使用**“文件”**菜单保存关系图。

    - 或 -

    若要将关系图另存为特定项目的一部分,请打开关系图图面的快捷菜单。 单击“移动”<DependencyGraphName.dgml>、“进入”以及你想要用于保存关系图的项目。

    Visual Studio 将关系图另存为 .dgml 文件,以便你可与 Visual Studio Ultimate、Visual Studio Premium 和 Visual Studio Professional 的其他用户共享。

    备注

    在你与使用 Visual Studio Premium 和 Visual Studio Professional 的用户共享关系图之前,请确保扩展所有组、显示隐藏节点和跨组链接,并检索你希望其他人在你的关系图上查看的所有已删除的节点。否则,其他用户将无法查看这些项目。

    保存建模项目中的图形或从建模项目复制到其他位置的图形时,可能会出现以下错误:

    “无法在项目目录外保存 fileName。不支持链接的项。”

    Visual Studio 将显示错误,但还是会创建保存的版本。若要避免错误,请在建模项目外创建图形。然后,可将图形保存到所需的位置。若只是将文件复制到解决方案中的其他位置,那么尝试保存图形将不起作用。

将关系图导出为图像以便将它复制到其他应用程序,如 Microsoft Word 或 PowerPoint

  1. 打开关系图表面的快捷菜单。 依次单击“编辑”、“复制图像”。

  2. 将该图像粘贴到另一个应用程序中。

将关系图导出为 XPS 文件,以便你可以在 XML 或 XAML 查看器(如 Internet Explorer)中查看它

  1. 打开关系图表面的快捷菜单。 单击“另存为 XPS”。

  2. 浏览到你要保存文件的位置。

  3. 命名关系图。 确保将**“保存类型”框设置为“XPS 文件(*.xps)”。 单击“保存”**。

以编程方式创建关系图

若要以批处理模式生成关系图文档(.dgml 文件),请运行 GraphCmd.exe 命令行工具。 例如,通过在每次生成后运此工具,可查找各个生成之间的已更改的依赖关系。 若要查找此工具,请在此文件夹中进行查找:C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE。

GraphCmd.exe 仅支持 .NET 代码并仅为程序集或 .dgml 文件生成依赖项信息,而不会为 Visual Studio 解决方案或项目文件中的源代码生成此类信息。 由于 GraphCmd.exe 是在 Visual Studio 外部运行的,因此对 DGQL 查询中的操作的支持是有限的。

GraphCmd.exe 的语法为:

GraphCmd -? -all -exceptions -input File_Name -query File_Name -exec "DGQL_Statement" -output File_Name -path alias=path

下表描述 GraphCmd.exe 的选项:

可多次指定以下选项:-input-query-exec-path

-?

显示 GraphCmd.exe 的帮助信息。

-all

包括所有中间查询结果,而不仅仅是最后一个节点集的中间查询结果。

-exceptions

以关系图文档 (.dgml) 文件的形式报告查询异常。

-input File_Name

处理指定的 .dgml 文件。

这可用于后期处理大型 .dgml 文件并对其进行筛选,以便能够在 Visual Studio 中更轻松地将该文件可视化。

-query File_Name

运行指定的定向关系图查询语言(DGQL 或 .dgql)文件。

请参阅:

-exec "DGQL_Statement"

运行指定的 DGQL 语句。

请参阅了解定向关系图查询语言 (DGQL)。

-output File_Name

输出指定的 .dgml 文件。

-path alias=path

指定一个在 DGML 文档的输入和输出中使用的新别名。

例如:

GraphCmd -output MyGeneratedGraph.dgml -path "MyPathAlias=C:\Program Files\..."

请参阅常用路径的别名。

常用路径的别名

常用路径的别名将减小 .dgml 文件的大小,并减少加载或保存该文件所需的时间。 若要创建别名,请在 .dgml 文件的结尾处添加 <Paths></Paths> 部分。 在此部分添加 <Path/> 元素以定义路径的别名:

<Paths>
   <Path Id="MyPathAlias" Value="C:\...\..." />
</Paths>

若要从 .dgml 文件中的某个元素引用别名,请用美元符号 ($) 和括号 (()) 将 <Path/> 元素的 Id 括起来:

<Nodes>
   <Node Id="MyNode" Reference="$(MyPathAlias)MyDocument.txt" />
</Nodes>
<Properties>
   <Property Id="Reference" Label="My Document" DataType="System.String" IsReference="True" />
</Properties>

若要编辑 .dgml 文件,请参阅编辑和自定义依赖项关系图

了解“定向关系图查询语言 (DGQL)”的更多信息。

DGQL 是一种可用于生成 DGML 的轻量查询语言。 DGQL 语句遵循以下节点选择和操作的交替模式:每个节点选择为下一个操作创建输入,而下一个操作的输出将成为下一个节点选择的输入,依此类推。

DGQL 语句的格式为:

<node selection> / <action> / <node selection> / <action> / ...

下表描述用于选择节点的 DGQL 语法:

*

选择所有节点。

+ "text"

选择所有包含“text”的节点。

+ Id.Equals("text")

选择所有其 Id 等于“text”的节点。

+ Background.Contains("text")

选择所有其 Background 特性具有包含字符串“text”的值的节点。

+ "text1" + "text2" + ...

选择所有匹配“text1”或“text2”的节点。

+ MyProperty="True"

选择所有具有名为 MyProperty 的属性(其值为“True”)的节点。

- Label.Contains("text")

选择所有节点,具有包含 (Contains) 字符串“text”的 Label 特性的节点除外。

+ Category.Is("MyCategory")

选择所有具有名为 MyCategory 的类别的节点或从 MyCategory 继承的节点。

下表描述了可对所选节点执行的直接操作的示例:

示例操作

描述

Microsoft.Contains

返回输入节点所包含的所有节点。 可以将 Contains 替换为一个不同的链接类别。

Microsoft.Open

打开输入节点的源代码。

备注

此操作仅在 Visual Studio 中有效。

Microsoft.AllOutBoundLinks

返回作为来自输入节点的传出链接的目标的所有节点。

Microsoft.AllInboundLinks

返回作为指向输入节点的链接的源端的所有节点。

Microsoft.Core.CreateGroupsByProperties

调用 GroupByProperties 操作。

Microsoft.AllNodes

返回目前为止整个关系图中包含的所有节点。

数据驱动的操作仅基于输入节点和链接中的数据选择项。 在使用数据驱动的操作匹配类别时,将包含继承的类别。 下表描述数据驱动的操作的示例:

类型

描述

Node:Both:Category

返回具有类别 Category 并通过指向任一方向的链接与输入节点连接的所有节点。

Link:Both:Category

返回通过指向任一方向的链接与输入节点连接并具有类别 Category 的所有节点。

Link:Backward:Category

返回利用具有类别 Category 的链接指向输入节点的所有节点。

Link:Forward:Category

返回利用具有类别 Category 的链接从输入节点指向的所有节点。

提示

  • 通常,对于一组给定的输入节点存在一个“默认”操作,此操作由体系结构资源管理器自动选定。 若要获取相同的行为,请使用空操作://

  • 由于空白在 DGQL 中没有意义,因此必要时你可以设置查询的格式以适合某个行。 在使用带有 GraphCmd 的 –exec 选项时,这将很有用。

  • 在调试 DGQL 时,使用体系结构资源管理器中的操作“Execute Expanded"”可帮助你查看查询的每个步骤,并查找未产生预期结果的步骤。

示例

下面的 DGQL 语句执行一条查询,如下列步骤中所述:

+ Id.Equals("Microsoft.Solution.ClassView") / "Microsoft.Solution.ClassView" / * / "Node:Both:CodeSchema_Class" / + CodeSchemaProperty_IsPublic.Equals("True")
  1. 单击“体系结构资源管理器”第一列中的“类试图”。

  2. 执行操作“Microsoft.Solution.ClassView"”,这将返回解决方案中的所有命名空间。

  3. 使用 * 选择所有命名空间。

  4. 通过指向任一方向的链接选择具有 CodeSchema_Class 类别且与这些命名空间相关的所有节点。 它们通常是包容链接。

  5. 仅从生成的类中筛选出具有属性 CodeSchemaProperty_IsPublic="True" 的类。

从技术上说,"Microsoft.Solution.ClassView" 操作不是必需的操作,因为它是**“类视图”**节点的“默认”操作。 因此,可以将此操作替换为 // 以简化查询,并在单个行上设置其格式,如下所示:

+Id.Equals("Microsoft.Solution.ClassView")//*/"Node:Both:CodeSchema_Class"/+CodeSchemaProperty_IsPublic.Equals("True")

我还能执行什么操作?

在何处可以获取详细信息?

类别

链接

论坛

博客