Access your C# Projects Through Code With Roslyn

Roslyn allows us to access our code through code. That permits us to analyse and work with code in a way that was impossible before. In this post we look at the basic parts of working with a Visual Studio solution to figure out what parts make up our application.

The syntax of Roslyn has not changed much in the 5 years since my first experiments. However, the same is not true for the dependencies and the things that work behind the API. Here we need a new combination of Roslyn and its dependencies to explore our solutions through code.

 

Preparations for .Net 7

Make sure that your Roslyn Project is on .Net 7 and add these 3 packages using the Package Manager console:

Those versions work together, but they will not work in .Net 6 or any other older version.

 

Read your solution file

The simplest starting point is to load the solution into a workspace. That allows us to iterate through our projects and list them on the console:

For my NUnit solution the code will produce this output:

Project MyBizLogic [0967cfce-a386-41ac-965f-aefc512ecf37]

Project TestsForNUnit2 [e1a15f36-4f86-44ac-910e-705ef47bb1bd]

Project TestsForNUnit3 [37fec393-c860-4c20-9aa8-f9490aaff268]

 

Find the project dependencies

We can iterate over our projects in the solution and explore the projects it depends on through the property AllProjectReferences:

That gives us this output:

Project ‘Microsoft.CodeAnalysis.Project’ depends on:

Project ‘Microsoft.CodeAnalysis.Project’ depends on:
– 0967cfce-a386-41ac-965f-aefc512ecf37

Project ‘Microsoft.CodeAnalysis.Project’ depends on:
– 0967cfce-a386-41ac-965f-aefc512ecf37

The GUID to reference the projects is great to compile code, but not so much to understand what is going on. A simple fix for a human-readable name is to iterate twice through your project list, the first time to create a dictionary that maps the GUID to the project name, and then we iterate through the projects to show their dependencies:

The output shows us that both our test projects reference the MyBizLogic project – this time in an understandable manner:

Project ‘Microsoft.CodeAnalysis.Project’ depends on:

Project ‘Microsoft.CodeAnalysis.Project’ depends on:
– MyBizLogic

Project ‘Microsoft.CodeAnalysis.Project’ depends on:
– MyBizLogic

Unfortunately, there is no way to access the referenced packages from Roslyn.

 

Helper methods for classes and interfaces

We can access interfaces and classes through the same methods. Therefore, I created these 3 helper methods to write the code only once:

 

List the interfaces

With the helper methods in place, we can filter the nodes for the type InterfaceDeclarationSyntax and iterate through the results:

When we run the code, we get the interface and its methods:

Interfaces in MyBizLogic:
– [IDebtCalculator – interface]
    * BatchProcessing()
    * ByMethod()

 

List the classes

To get the classes in a project, we filter for ClassDeclarationSyntax and iterate through the result:

This shows us all classes and their methods in our solution:

Classes in MyBizLogic:
– [DebtCalculator – class]
    * ByMethod()
    * BatchProcessing()
– [MyException – class]

Classes in TestsForNUnit2:
– [DebtCalculatorTestOld – class]
    * SetUp()
    * Calculation_can_only_be_called_with_valid_CalculatorMethods()
    * Extended_calculation_isnt_allowed()
    * Data_can_be_loaded_from_file_system()
    * Something()

Classes in TestsForNUnit3:
– [DebtCalculatorTestNew – class]
    * SetUp()
    * Calculation_can_only_be_called_with_valid_CalculatorMethods()
    * Extended_calculation_isnt_allowed()
    * Extended_calculation_isnt_allowed_CheckInstanceOf()
    * Data_can_be_loaded_from_file_system()
    * Something()

 

List the enumerations

To get the definitions for enumerations in a project, we need to filter for EnumDeclarationSyntax and use the Members property to get the named constants:

This lists us the enumerations, its defined constants and their corresponding int value:

Enums in MyBizLogic:
– [CalculatorMethod – enum]
    * Basic = 0
    * Extended = 1

 

Next

Roslyn allows us to work with our code base through code. We can access classes, interfaces and projects without writing much code. From the basic examples in this post, you can build on and dive a lot deeper into the other packages that come with Roslyn.

Next week we use Roslyn to create a dependency graph of our projects and write a bit of Python code to analyse it.

1 thought on “Access your C# Projects Through Code With Roslyn”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.