简体   繁体   中英

How can I get class dependencies programmatically and their respective file locations?

I need to get some sort of a dependency graph between classes of a given project ie all the classes which that specific class uses. I want to know which classes a given class is using so that I can later find their file path within a project. Consider the following simple example:

public class Dog: Animal, IBark
{
    public void Bark()
    {
        // Code to bark.
    }

    public void Fight(Cat cat)
    {
        // Code to fight cat.
    }
}

For this specific example, I would like to know which classes the Dog class uses. So I would like to programmatically get access to an object that has those dependencies. In this situation, that object would contain the IBark , Animal and Cat classes/interfaces and possibly their respective file paths.

Is this possible in C#? I have tried looking into the Roslyn API and although I can parse the document and traverse it to find the nodes I have not found a way to get metadata related to those nodes that could possibly give me what I am looking for (eg file paths). This got me wondering if there is not a better approach to this problem out there.

This can be done with Roslyn apis. The algorithm is the following:

  1. Load solution (.sln)
  2. Iterate through projects (.csproj)
  3. Iterate through documents (.cs) within the project
  4. Load semantic model for the document
  5. Get SyntaxTree and traverse all SyntaxNode
  6. Detect each SyntaxNode concrete type. If detected syntax is a class definition (let's say Dog) - continue to traverse considering that further detected class or interface depend on Dog

Sample code below. Also I committed this in github . You will be interested in sample unit tests and sample solution based on your example . I did an assumption that single file contains only one class definition, however I think that this should be enough for you to start.

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

For the code above workspace is loaded in the following way:

var workspace = MSBuildWorkspace.Create();
await workspace.OpenSolutionAsync(solutionFilePath);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM