Test-driving C# Source Generators

No Comments

C# 8 will ship soon with .Net Core 5, and one of the most exciting features is Source Generators. These introduce the ability to add code during compilation, e.g. add a strongly typed accessor library for CSV files or automatically implement a REST interface. Generators work with the current preview (8), but they are not exactly user-friendly. Particularly, documentation is lacking and the ability to debug them is not great. But even so, they can be very powerful tools and I decided to give them a try.

For years I resented the need to write countless interfaces for the sake of dependency injection (DI) and testability – e.g. you implement the User class and then you need to have an IUser interface because Asp.Net core DI works best with interfaces. These interfaces are often nothing but noise, you generate and change them driven by the needs of the class, not because the interface has a value of its own.
So they are perfect to automate away: let’s generate them with a Source Generator and we will never have to think about them again.

Implementation – work in progress

I uploaded the results of my first attempt on GitHub: AutomaticInterface. This is currently a total work in progress, but if you download the newest .Net Core Preview (Preview 8 as of today) and the Visual Studio Preview, you should be able to build and execute the project.

The interesting bits happen in DemoClass.cs and Program.cs

The DemoClass is a very simple Class, with just a property:

using AutomaticInterfaceAttribute;
 
namespace AutomaticInterfaceExample
{
    [GenerateAutomaticInterface]
    class DemoClass: IDemoClass
    {
        public string Hello { get; set; }
    }
}

Note that IDemoClass is not implemented by the user code at all, but it will work at runtime:

using System;
 
namespace AutomaticInterfaceExample
{
    class Program
    {
        static void Main(string[] args)
        {
 
            DemoClass demo = new DemoClass();
            IDemoClass demoInterface = demo;
 
            Console.WriteLine("Hello World!");
        }
    }
}

The magic happens in the Source Generator, which is run when compiling the project and can be found here.

Currently, this supports only simple properties, but I hope to expand that over the next few weeks.

Current issues

Source Generators are still very much WIP, so there are some stumbling blocks:

Documentation is sparse

There is not much documentation beyond the repo and some aging blog posts. The one additional good source is this GitHub repo: ObservableTests. I very much based my testing on this repo.

Debugging is painful

Currently debugging the generator when using it seems to be impossible. I was able to debug it in the unit tests using Debugger.Launch() and that is helpful. This is compounded by the fact that the Source Generator is completely opaque at the moment. When run, you will never see the generated source code, making bug hunting very difficult. Due to this, I dump the code into a file at the moment. This should be resolved for release, though.

Testing is difficult

You can invoke the tests in a unit test, but since the result is a compiled class, writing meaningful tests is hard. I will try to see if I can use code analysis to see if the correct interface was generated.

Random restarts of Visual Studio is required

If Visual Studio refuses to see an auto-generated piece of code, try restarting VS.

Very ugly writing experience

The most annoying problem is that you need to generate your source code as text, with very little help from the compiler. So it’s basically just string concatenation and hoping for the best. Getting C# to concatenate just right is painful and harder than it should be.
Since the source analysis operates on objects of the Microsoft.CodeAnalysis.Analyzers namespace, this feels especially annoying – you are analyzing well-formed abstractions of source code, but are unable to use them to generate the target code automatically.
T4 templates are sometimes mentioned as a solution, but I have no experience writing them and documentation on this is sparse.

Outlook

Overall I am really excited about Source Generators; they close a huge gap in the .Net ecosystem. They are currently somewhat annoying to use and I hope that the issues outlined above get straightened out for the final release.

I would welcome any contribution to AutomaticInterface – I would really like to expand this to a workable implementation.

Christian Sauer

Christian Sauer works as an IT Consultant for codecentric Solingen. He works mainly on C# or Python-based web applications. Also, he loves to build applications that bridge the gap between Data Science and more traditional applications.
Last but not least he loves cloud native applications and DevOps.

More content about Software Engineering

Software Engineering

Hexagon, Schmexagon? – Part 2

Software Engineering

Hexagon, Schmexagon? – Part 1

Comment

Your email address will not be published. Required fields are marked *