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:
semantic model
for the document SyntaxTree
and traverse all SyntaxNode
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.