Source Generators
Source Generators are part of Roslyn feature that automatically generates code during the compilation process.
Why Source Generators
Alternatıve to Reflection
It is compile time not runtime
Unblock AOT trimming
It is just code
Demo
The code produces the below output.
static void Main(string[] args)
{
var classTypes = Assembly.GetEntryAssembly()
.GetTypes()
.Where(c => c.IsClass && c.IsPublic)
.Select(c => c.FullName);
foreach (var classType in classTypes)
{
Console.WriteLine(classType);
}
}
PublishAot
If you have enabled PublishAot, it will publish to machine code and remove all unused references. Since our classes (Student, Course) are not reference, they will no be included in the published code and the output will be empty.
Creating Source Generator
To use Source Generator, the project must target netstandard2.0. So, create a new class library with netstandard2.0.
Add reference for the below packages.
Microsoft.CodeAnalysis.Analyzers
Microsoft.CodeAnalysis.CSharp
Add the reference as below
<ProjectReference Include="..\Generator\Generator.csproj" OutputItemType="Analyzer" />
Make the changes in the Generator class.
namespace Generator;
[Generator]
public class TheGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.SyntaxProvider.CreateSyntaxProvider(
predicate: static(node, _) => node is ClassDeclarationSyntax,
transform: static (ctx, _) => (ClassDeclarationSyntax)ctx.Node
).Where(c => c is not null);
var compilation = context.CompilationProvider.Combine(provider.Collect());
context.RegisterSourceOutput(compilation, Execute);
}
private void Execute(SourceProductionContext context, (Compilation Left, ImmutableArray<ClassDeclarationSyntax> Right) tuple)
{
var (compilation, list) = tuple;
var namelist = new List<string>();
foreach (var systax in list) {
var symbol = compilation.GetSemanticModel(systax.SyntaxTree)
.GetDeclaredSymbol(systax) as INamedTypeSymbol;
namelist.Add($"\"{symbol.ToDisplayString()}\"");
}
var names = string.Join(",\n ", namelist);
var theCode = $$"""
namespace Generator;
public static class ClassNames {
public static List<string> Names = new(){
{{ names }}
};
}
""";
context.AddSource("YourClassList.g.cs", theCode);
}
}
Reference
https://www.youtube.com/watch?v=Yf8t7GqA6zA&list=PLdo4fOcmZ0oULyHSPBx-tQzePOYlhvrAU&index=11
Subscribe to my newsletter
Read articles from İbrahim Uludağ directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
İbrahim Uludağ
İbrahim Uludağ
An agile-minded senior developer with a proven track record spanning over 15 years of developing innovative end-to-end business solutions. Have experience in architecture, development, test, UX, and team lead. Designed, led, developed, and released solutions for different areas including eLearning, law, telecommunication, travel&tourism, insurance, and fraud detection. Focus on clean architecture, clean code, and satisfied customers. Tech stack is mainly full-stack development in the .NET ecosystem and Azure.