C# 如何以编程方式获取类依赖项及其各自的文件位置?

C# 如何以编程方式获取类依赖项及其各自的文件位置?,c#,.net-core,roslyn,roslyn-code-analysis,C#,.net Core,Roslyn,Roslyn Code Analysis,我需要得到给定项目的类之间的某种依赖关系图,即该特定类使用的所有类。我想知道给定类正在使用哪些类,以便以后可以在项目中找到它们的文件路径。考虑下面的简单例子: 公共级犬:动物,伊巴克犬 { 公共空间 { //吠叫的代码。 } 公众无效斗殴(猫) { //打猫的密码。 } } 对于这个特定的例子,我想知道Dog类使用哪些类。因此,我希望通过编程方式访问具有这些依赖项的对象。在这种情况下,该对象将包含IBark、Animal和Cat类/接口以及它们各自的文件路径 这在C#中可能吗?我曾尝试查看Ro

我需要得到给定项目的类之间的某种依赖关系图,即该特定类使用的所有类。我想知道给定类正在使用哪些类,以便以后可以在项目中找到它们的文件路径。考虑下面的简单例子:

公共级犬:动物,伊巴克犬
{
公共空间
{
//吠叫的代码。
}
公众无效斗殴(猫)
{
//打猫的密码。
}
}
对于这个特定的例子,我想知道
Dog
类使用哪些类。因此,我希望通过编程方式访问具有这些依赖项的对象。在这种情况下,该对象将包含
IBark
Animal
Cat
类/接口以及它们各自的文件路径


这在C#中可能吗?我曾尝试查看Roslyn API,虽然我可以解析文档并遍历它以找到节点,但我没有找到一种方法来获取与这些节点相关的元数据,这些元数据可能会提供我正在查找的内容(例如,文件路径)。这让我怀疑是否有更好的方法来解决这个问题。

这可以通过
Roslyn
API来实现。算法如下所示:

  • 加载解决方案(.sln)
  • 迭代项目(.csproj)
  • 迭代项目中的文档(.cs)
  • 加载文档的
    语义模型
  • 获取
    SyntaxTree
    并遍历所有
    SyntaxNode
  • 检测每个
    SyntaxNode
    具体类型。若检测到的语法是一个类定义(比如Dog)——考虑到进一步检测到的类或接口依赖于Dog,继续遍历
  • 下面是示例代码。我也是在这件事上犯的。您将对和感兴趣。我假设单个文件只包含一个类定义,但是我认为这应该足够让您开始

            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);