Along with .NET 5, Microsoft released C# Source Generators.
And after creating my first generator, I consider it one of the coolest features .NET developers can use.
But what are Source Generators?
They are C# programs that can analyze code, dynamically generate files and inject them into the build pipeline.
Use cases?!
- Generate C# classes from JSON
- Extend a POCO class with INotifyPropertyChanged
- Generate builders from POCO classes
- Generate mapping extension methods to replace AutoMapper
Super basic example
Each generator has 2 methods: one to analyze the existing code and one to generate new code.
[Generator]
public class MyGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context) { }
public void Execute(GeneratorExecutionContext context) { }
}
To generate a C# class:
var source = @"
namespace Dev.To {{
public class Post {{
public string Title {{ get; set; }}
}}
}}";
context.AddSource("Post.cs", SourceText.From(source, Encoding.UTF8));
It might not seem much; however, think about what you can do with partial classes or extensions methods.
How I tried to use them
If you work with .NET Core you might be familiar with appsettings.json
.
We often need to create POCO classes representing the JSON and then register them in Startup to be injected later with IOptions<>
.
Why don't we let source generators do the heavy lifting for us?
So, I create a preview NuGet that does exactly that!
- It reads
appsettings
content - For each object property it creates a new C# class
- It creates a partial Startup class with a private
RegisterOptions
method that register the new classes withservices.Configure<PropertyName>(Configuration.GetSection(nameof(PropertyName)));
- The only thing people need to do is making their
Startup
partial and callRegisterOptions
inConfigureServices
method.
Given this JSON:
{
"MyOtherOptions": {
"MyString": "any",
"MyInt": 1,
"MyDouble": 1.1,
"MyBool": true,
"MyObject": {
"MyObjectString": "any"
},
"MyArray": [ "any" ]
}
}
It generates these classes:
Generated content:
// MyOtherOptions.cs
public class MyOtherOptions
{
public string MyString { get; set; }
public int MyInt { get; set; }
public double MyDouble { get; set; }
public bool MyBool { get; set; }
public MyObject MyObject { get; set; }
public string[] MyArray { get; set; }
}
// Startup.Generated.cs
public partial class Startup
{
private void RegisterOptions(IServiceCollection services)
{
services.Configure<MyOtherOptions>(Configuration.GetSection(nameof(MyOtherOptions)));
}
}
Final words
As you can see, there's a lot of potential behind this new feature.
It will not replace Reflection completely but it can drastically improve performance for a lot of libraries!
However, since it's in preview, there are limitations, and things might change, so keep that in mind!
The code for my example can be found here on GitHub.
Top comments (0)