Source generators to boost performance in .NET 5

C-Sharp Source generators are performance catalyst to .NET 5

In April 2020, Microsoft announced its first previews of .NET 5, aimed at unifying the .NET platform. .NET 5 offers so many promising features that Microsoft skipped version 4 to leapfrog right to .NET 5. With .NET 5, Microsoft joins the trend of other SDKs. .NET 5 offers a unified experience, a single BCL across all its applications and improved native and web apps for many devices and operating systems. In other words, projects for one device will work across Windows, Android, and iOS with native controls.

Early reviews tout improvements to garbage collection procedures and the RyuJIT code quality, but the technology that may wow us all are Source Generators, which compliment Roslyn Analysers, runtime reflection code, and Type Providers in F#. So, what are Source Generators? What do they do that enhances code?

What are Source Generators

They’re so new that one may infer from reading the Source Generator Design Document, as well as Microsoft’s development blog, that their capacities are not fully evident. What we know is that they are promising new technologies. They are metaprogramming tools that developers can sandbox to explore best uses.

So, developers, here are the basics to whet your appetite and help you become an early adopter of this technology.

>> Let’s dive deeper.

Source Generators are code to be used as part of C# compilation to inspect a program and generate additional files to be compiled together. According to Microsoft, they allow for retrieval of a compilation object that represents all the code being compiled. First they inspect and allow coders to write code that fits with the syntax and semantic models of the code being compiled, i.e. improve or enhance software in the development process. They also generate C# source files to add to the compilation. Finally, they input additional source code automatically while compiling.

Source Generator Enhance SDK

Encoding Source Generators into your SDK allows you to complete the controller discovery process at compilation, not at the first start up. They can reduce stringly-typed code, which can create problems for other developers to understand. Stringly-typed code often results in runtime errors. Source Generators allow for strongly-typed routing, and string types to be generated at compilation. In the MSBuild C# task, Source Generators can reduce total calls to the compiler because the MSBuild tasks don’t have to be balanced or traded off. The new code allows for better abstraction in the task.

Design Goals For This New Technology

According to the Source Generator Design Document, the goals for the generators look like this.

  • They will produce code strings to be added at compilation as a result of analysis.
  • They will be additive only. (No modifying existing code)
  • They will produce diagnostics (see below on why they will not replace analysers, reflection, et cetera) and if they cannot generate source code, they will inform the user.
  • They may access non-C# source texts.
  • They run un-ordered. There can be multiple generators (for each object) that see the same input compilation but not access files created by other Source Generators. In accessing additional analyzer files in the compiler, coders can make generation decisions based on more than one user’s C# code.
  • Users can specify generators to run via assemblies (which may be a mix of generators and analyzers). Because these are external assemblies, the generator will not build the assembly in which it exists.

Comparing Source Generators with Other Code Analysers

Microsoft’s development blog indicates that Source Generators do not replace Roslyn Analysers, Runtime Reflection or Type Providers in F#. Here’s why:

  • Roslyn Analyzers are also a compiler feature. Analyzers also emit diagnostics, but those are used for the code fix. They are push-based and will follow the tree. Analyzers allow you to register for analyzing events and elements critical to your software. Analyzers allow coders to produce events for more diagnostic data. On the other hand, Source Generators are pull-based. As they add source code, they may not follow the tree or construct the symbol tables. In short, the two together will enhance diagnostic data to strengthen the program. One will allow for analysis of source code; the other will look at specific elements.
  • Runtime Reflection Code still matters. Though Source Generators offer diagnostics and source code, reflection remains a critical tool regarding performance and other challenges.
  • Type Providers in F# inspired Source Generators to a small degree. Of course, the former are for F# language, and the latter remit only C# source code, not types, properties, et cetera. Whereas Type Providers are based on external sources, Source Generators focus on C# code compilation, though they can analyze some other files. At this time, there are no Source Generators in F#.

Developers who first looked at the previews have asked if Source Generators will be able to modify or rewrite existing code, somewhat like Type Providers in F#. However, the .NET development team predicts it will not allow for that feature because the powerful benefit of Source Generators is that they keep code predictable at runtime.

Conclusion

Looking ahead to Source Generators in future previews (and in the upcoming final version of .NET 5) is partially up to developers. Microsoft invites C# library developers to try out Source Generators to sandbox their potential. With feedback, they hope to improve and better use the technology. At this time, their design may change. Microsoft’s .NET 5 team is focusing on the user editing experience as well as modifications to the API. For this reason, they want to generate buzz and code, pun intended, as well as feedback. Now is the time for .NET developers to influence the technology to make it more useful. Now is the time for coders to play.