c# - 如何以编程方式获取类依赖项及其各自的文件位置?
问题描述
我需要在给定项目的类之间获取某种依赖关系图,即该特定类使用的所有类。我想知道给定类正在使用哪些类,以便以后可以在项目中找到它们的文件路径。考虑以下简单示例:
public class Dog: Animal, IBark
{
public void Bark()
{
// Code to bark.
}
public void Fight(Cat cat)
{
// Code to fight cat.
}
}
对于这个特定的示例,我想知道Dog
该类使用哪些类。所以我想以编程方式访问具有这些依赖项的对象。在这种情况下,该对象将包含IBark
、Animal
和Cat
类/接口以及可能它们各自的文件路径。
这在 C# 中可能吗?我曾尝试查看 Roslyn API,虽然我可以解析文档并遍历它以找到节点,但我还没有找到一种方法来获取与那些可能给我正在寻找的内容的节点相关的元数据(例如文件路径) . 这让我想知道是否没有更好的方法来解决这个问题。
解决方案
这可以通过Roslyn
api 来完成。算法如下:
- 加载解决方案 (.sln)
- 遍历项目 (.csproj)
- 遍历项目中的文档 (.cs)
semantic model
为文档加载- 获取
SyntaxTree
并遍历所有SyntaxNode
- 检测每种
SyntaxNode
具体类型。如果检测到的语法是类定义(比如说 Dog) - 继续遍历,考虑到进一步检测到的类或接口依赖于 Dog
下面的示例代码。我也在github中提交了这个。您将对基于您的示例的示例单元测试和示例解决方案感兴趣。我假设单个文件只包含一个类定义,但是我认为这应该足以让您开始。
var dependencies = new Dictionary<string, List<string>>();
//key - class name, value - list of dependent class names
var project = workspace.CurrentSolution.Projects.First();
foreach (var document in project.Documents)
{
var semanticModel = await document.GetSemanticModelAsync();
KeyValuePair<string, List<string>>? keyValue = null;
foreach (var item in semanticModel.SyntaxTree.GetRoot().DescendantNodes())
{
switch (item)
{
case ClassDeclarationSyntax classDeclaration:
case InterfaceDeclarationSyntax interfaceDeclaration:
if (!keyValue.HasValue)
{
keyValue = new KeyValuePair<string, List<string>>(semanticModel.GetDeclaredSymbol(item).Name, new List<string>());
}
break;
case SimpleBaseTypeSyntax simpleBaseTypeSyntax:
keyValue?.Value.Add(simpleBaseTypeSyntax.Type.ToString());
break;
case ParameterSyntax parameterSyntax:
keyValue?.Value.Add(parameterSyntax.Type.ToString());
break;
}
}
if (keyValue.HasValue)
{
dependencies.Add(keyValue.Value.Key, keyValue.Value.Value);
}
}
对于上面的代码,工作区的加载方式如下:
var workspace = MSBuildWorkspace.Create();
await workspace.OpenSolutionAsync(solutionFilePath);
推荐阅读
- react-native - navigation.navigate() 不适用于我的嵌套导航
- solr - 如何在 solr-operator helm chart 中使用身份提供者
- css - 反应原生文本不能在嵌套父视图中使用 ellipsizeMode,宽度:0,flex:1
- python - 合并具有一致标签名称的数据框
- unit-testing - gmock-generated-actions.h 中的 Gmock 编译错误
- c - CMAKE生成依赖于共享库的静态库
- c# - Header 中自定义字段的不记名令牌
- kubernetes - 我的 pod 状态显示 OOM-killed,但没有重新启动容器。为什么?
- openapi - 如何在 OpenAPI 中为 HAL 格式的模式指定强制和可选链接?
- mongodb - 为什么我的 Mongoose Schema 唯一验证在第一次运行时不起作用?