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