C# Generated Code
Generated code is the source text a generator emits for a marked class. The compiler compiles that text together with the hand-written code.
The Report generator
This generator source is a library the compiler loads. It emits a Describe method for each marked class.
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
[Generator]
public class ReportGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classes = context.SyntaxProvider.CreateSyntaxProvider(
(node, _) => node is ClassDeclarationSyntax,
(ctx, _) => (ClassDeclarationSyntax)ctx.Node)
.Where(c => c.AttributeLists.SelectMany(a => a.Attributes)
.Any(a => a.Name.ToString() == "Report"));
context.RegisterSourceOutput(classes, (spc, cls) =>
{
int fields = cls.Members.OfType<FieldDeclarationSyntax>().Count();
string source = "partial class " + cls.Identifier.Text + "\n{\n public string Describe()\n {\n return \"" + cls.Identifier.Text + " has " + fields + " fields\";\n }\n}\n";
spc.AddSource(cls.Identifier.Text + ".Report.g.cs", source);
});
}
}The consumer pair for Meter
This program pairs the hand-written Meter class with its generated part. The compiler joins the two parts into one type.
using System;
[AttributeUsage(AttributeTargets.Class)]
class ReportAttribute : Attribute
{
}
[Report]
partial class Meter
{
public string Name = "Flow";
public int Speed = 7;
public int Range = 9;
}
// The file the generator adds at build time:
partial class Meter
{
public string Describe()
{
return "Meter has 3 fields";
}
}
class Program
{
static void Main(string[] args)
{
Meter meter = new Meter();
Console.WriteLine(meter.Describe());
}
}Example
using System;
[AttributeUsage(AttributeTargets.Class)]
class ReportAttribute : Attribute
{
}
[Report]
partial class Valve
{
public string Name = "Main";
public int Size = 3;
public bool Open = true;
public int Level = 4;
}
// The file the generator adds at build time:
partial class Valve
{
public string Describe()
{
return "Valve has 4 fields";
}
}
class Program
{
static void Main(string[] args)
{
Valve valve = new Valve();
Console.WriteLine(valve.Describe());
}
}Key points
- The generator in this lesson finds classes marked with a Report attribute.
- It counts the fields declared in each marked class.
- It emits a partial class with a Describe method for that class.
- The Describe method returns the class name and its field count as text.
- The stated output of the generator snippet is the exact file text it emits for the Sensor class.
In this example, the Valve class declares four fields. The generator counts those fields for its generated text. The generated part adds a Describe method that reports four fields. Main creates a Valve and prints the result of that method.
Note
The generator runs during compilation, before the program itself runs.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does the Report generator emit for a marked class?