Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C# & .NET (C# 14, .NET 10 LTS)  Module 18 – Reflection, attributes and source generators

Using source generators in .NET

Use the source generators that ship with .NET for JSON, regex, logging, options and P/Invoke, read the code they write, and fix the warnings they report.

  • Advanced
  • 15 minutes
  • Examples run with .NET 10.0.401 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 5 of 15 minutes free
Free: A source generator writes code into your build, next to yours · Partial members are the contract between your code and a generator · You can read every line a generator writes. With a pass: 3 in-depth parts and 3 interview answers, about 10 minutes.

What you will learn

  • Use the .NET source generators for JSON, regular expressions, logging, options validation and native calls
  • Inspect the files a generator writes with EmitCompilerGeneratedFiles, and read what they do
  • Explain why generators need partial members, and declare partial methods, properties, constructors and events
  • Compare reflection-based and generated code for trim and AOT warnings and for allocations
  • Diagnose the SYSLIB errors and warnings that generators report, and fix their cause

Before you start

What you’ll learn · Before you start

What you will learn

  • Use the .NET source generators for JSON, regular expressions, logging, options validation and native calls
  • Inspect the files a generator writes with EmitCompilerGeneratedFiles, and read what they do
  • Explain why generators need partial members, and declare partial methods, properties, constructors and events
  • Compare reflection-based and generated code for trim and AOT warnings and for allocations
  • Diagnose the SYSLIB errors and warnings that generators report, and fix their cause

Before you start

On this page

The same JSON and configuration code built with 0 warnings as ordinary code and with 6 once the trim and AOT analyzers looked at it, each one a call that a Native AOT build could break. Generating that code while the program is built removed all six, and the [LoggerMessage] generator took a log call from 64 bytes to 0.

You will see what a source generator is, use the generators that ship with .NET, read the files they write and learn why each one needs a partial member from you. Under every program is the output it gave on .NET 10.

A source generator writes code into your build, next to yours

A source generator: A component that runs inside the C# compiler and adds code to the program while it is built. The regex source generator turns each [GeneratedRegex] pattern into C# matching code. More in “Regular expressions with source generation” runs inside the C# compiler while your project builds. Roslyn’s design notes give it two powers and one limit: it reads the compilation, the compiler’s whole model of your code, and it adds new source files to it, but it may not modify code you wrote. .NET ships several:

You write Generator What it writes
[JsonSerializable] on a context class System.Text.Json the metadata that serialisation needs
[GeneratedRegex] on a partial property regular expressions the matching code for the pattern
[LoggerMessage] on a partial method logging the method that checks the level, then logs
[OptionsValidator] on a partial class options a validator for the rules on the options
[LibraryImport] on a partial method interop the marshalling around a native call
one property in the project file configuration binding the binding code behind each Get<T> and Bind call

The smallest is the regex generator. regex.cs checks four IFSC codes with a generated pattern and with the same pattern built while the program runs:

regex.cs: a [GeneratedRegex] property against a Regex built at run time C# · regex/regex.cs
// [GeneratedRegex] on a partial property: the regex source generator writes the matching code while the program is built.
using System.Text.RegularExpressions;

string[] codes = ["ABCD0001234", "ABCD1001234", "abcd0001234", "ABCD000123"];
Regex atRunTime = new(@"^[A-Z]{4}0[A-Z0-9]{6}$");
foreach (string code in codes)
    Console.WriteLine($"{code,-12} generated: {Codes.Ifsc.IsMatch(code),-5}  built at run time: {atRunTime.IsMatch(code)}");

Console.WriteLine($"type of the generated regex: derived from Regex: {Codes.Ifsc.GetType().IsSubclassOf(typeof(Regex))}");
Console.WriteLine($"type of the run-time regex: {atRunTime.GetType().Name}");
Console.WriteLine($"the same object on every read: {ReferenceEquals(Codes.Ifsc, Codes.Ifsc)}");

static partial class Codes
{
    // IFSC: four letters for the bank, then 0, then six letters or digits for the branch.
    [GeneratedRegex(@"^[A-Z]{4}0[A-Z0-9]{6}$")]
    public static partial Regex Ifsc { get; }
}

Output

ABCD0001234  generated: True   built at run time: True
ABCD1001234  generated: False  built at run time: False
abcd0001234  generated: False  built at run time: False
ABCD000123   generated: False  built at run time: False
type of the generated regex: derived from Regex: True
type of the run-time regex: Regex
the same object on every read: True

Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run regex.cs

Both gave the same answers. The generated one is a class derived from Regex that the generator wrote during the build, and the property hands out the same object on every read, while the run-time Regex parsed its pattern when the program ran. Step through a build in which four generators work at once:

Interactive · stage by stage One build of the generated project, with four generators in it Step through a build of the project generated. Each stage is a step of the compiler; the branch is what a mistake in your half does.
One build of the generated project, with four generators in it, step 6 of 6. Showing your .cs files, the compiler's model, the generators run, generated .cs files (their nine files, in obj/), one assembly. In focus: the generators run.a SYSLIB diagnosticyour .cs filespartial classes, attributesthe compiler's modelsyntax and typesthe generators runthey read the modelgenerated .cs filestheir nine files, in obj/one assemblyyour code and theirsSYSLIB diagnostic

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Your half. Program.cs declares BookingJson, Patterns.Pnr, Log.Booked and BookingLimitsValidator as partial members with attributes, and supplies no bodies for them.
  2. The model. The compiler parses the files and works out every type and member: the same model it uses to report errors and that your editor uses for completion.
  3. Generators read it. Each generator looks for its own attribute in that model: [JsonSerializable], [GeneratedRegex], [LoggerMessage] and [OptionsValidator]. It can read everything, but change nothing you wrote.
  4. They add files. They write the other halves as new source files: nine from these four, from the JSON context with one file per type to the single logging method.
  5. One compilation. The compiler compiles your files and the generated ones together into one assembly. At run time nothing distinguishes the generated code: no reflection, no files read.
  6. When your half is wrong. If a declaration does not fit, for example a context that is not partial, the generator writes nothing for it and reports a SYSLIB diagnostic instead, which the build shows like a compiler error.

Partial members are the contract between your code and a generator

A generator cannot change your code, so you declare the member and it supplies the body. That is the job of partial member: A method, property, indexer, constructor or event declared in one part of a partial type and implemented in another, often by a source generator. Only a private void method may be left without an implementation.: a declaring part without a body and an implementing part with one. partial.cs writes both halves by hand, as you and a generator would:

partial.cs: a partial constructor, property, method and event, and one left empty C# · partial/partial.cs
// The two halves of partial members, as your code and a generator share one type. Here both halves are in one file;
// a generator would write the second.
var ticket = new Ticket("4521873690");
ticket.Changed += what => Console.WriteLine($"event: {what} changed");
ticket.Passengers = 3;
Console.WriteLine(ticket.Describe());
ticket.Save();
Console.WriteLine($"after Save(): Saved = {Ticket.Saved}, since the call to OnSaved, ++Saved included, was removed");

// Your half: declarations only.
partial class Ticket
{
    public partial Ticket(string pnr);

    public partial int Passengers { get; set; }

    public partial string Describe();

    public partial event Action<string>? Changed;

    partial void OnSaved(int count);

    public static int Saved;

    public void Save() => OnSaved(++Saved);
}

// The other half: the implementations, as a generator would write them. OnSaved gets none.
partial class Ticket
{
    private readonly string _pnr;
    private int _passengers;
    private Action<string>? _changed;

    public partial Ticket(string pnr) => _pnr = pnr;

    public partial int Passengers
    {
        get => _passengers;
        set
        {
            _passengers = value;
            _changed?.Invoke(nameof(Passengers));
        }
    }

    public partial string Describe() => $"{_pnr}: {_passengers} passengers";

    public partial event Action<string>? Changed
    {
        add => _changed += value;
        remove => _changed -= value;
    }
}

Output

event: Passengers changed
4521873690: 3 passengers
after Save(): Saved = 0, since the call to OnSaved, ++Saved included, was removed

Recorded with .NET SDK 10.0.401 (runtime 10.0.12) on macOS 26 arm64. To run it yourself: dotnet run partial.cs

The constructor, the property, the method and the event each worked through their implementing part. OnSaved had none: a void partial method without an access modifier, which leaves it private, and without out parameters may be left unimplemented, and Microsoft’s reference says the compiler then removes it and its calls. The run proves the calls went with their arguments, since ++Saved never ran.

Each release let more kinds of member be partial, and each one gave generators a new place to fill in:

Timeline · 5 events in order Which members can be partial, release by release Walk through the releases in order. Each one widened what a generator can implement for you.
  1. C# 2

    Partial types

    A class, struct or interface can be split over several files, so a tool can own one file of a type while you own another.

  2. C# 3

    Partial methods

    A private void method may be declared in one part and implemented in another, or nowhere: then the compiler removes it and every call to it.

  3. C# 9

    Partial methods for generators generators

    Partial methods may be public, return values and take out parameters, and such a method must be implemented, which is the contract a generator fills.

  4. C# 13

    Partial properties and indexers generators

    A property can be declared partial too, which is how [GeneratedRegex] works on a property instead of a method.

  5. C# 14

    Partial constructors and events generators

    Instance constructors and events join the list; the implementing declaration of an event must write its add and remove accessors.

The timeline has 5 events, from C# 2 to C# 14.

Checkpoint

Check: What a source generator does · Partial members as the contract

  1. Question 1 of 2 Which of these can a source generator not do?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Change or remove code you wrote

    Because a generator cannot touch your code, it needs a place to put its code: a partial declaration of yours that it completes.

  2. Question 2 of 2 In partial.cs, Save() calls OnSaved(++Saved), and OnSaved is a private void partial method with no implementation. What did the run print for Saved?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 0, because the call and its argument were removed

    This is the same trap as a conditional method: keep effects out of the arguments of an optional partial method.

You can read every line a generator writes

<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> keeps a copy of each generated file under obj/. The project generated uses four generators of .NET and sets it:

generated/Program.cs C# · generated/Program.cs
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

var booking = new Booking("4521873690", 2);
Console.WriteLine(JsonSerializer.Serialize(booking, BookingJson.Default.Booking));
Console.WriteLine($"PNR well formed: {Patterns.Pnr.IsMatch(booking.Pnr)}");

using var factory = LoggerFactory.Create(builder => builder.AddProvider(new PrintProvider()));
Log.Booked(factory.CreateLogger("Bookings"), booking.Pnr, booking.Passengers);

ValidateOptionsResult result = new BookingLimitsValidator().Validate(null, new BookingLimits { MaxPassengers = 9 });
Console.WriteLine($"options valid: {result.Succeeded}; {result.FailureMessage}");

record Booking(string Pnr, int Passengers);

[JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
[JsonSerializable(typeof(Booking))]
partial class BookingJson : JsonSerializerContext;

static partial class Patterns
{
    [GeneratedRegex(@"^\d{10}$")]
    public static partial Regex Pnr { get; }
}

static partial class Log
{
    [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "Booked {Pnr} for {Passengers} passengers")]
    public static partial void Booked(ILogger logger, string pnr, int passengers);
}

class BookingLimits
{
    [Range(1, 6)]
    public int MaxPassengers { get; set; }
}

[OptionsValidator]
partial class BookingLimitsValidator : IValidateOptions<BookingLimits>;

// A logger that prints each event with its structured values, so the output shows what the generated method passes.
sealed class PrintProvider : ILoggerProvider
{
    public ILogger CreateLogger(string category) => new PrintLogger(category);

    public void Dispose() { }

    sealed class PrintLogger(string category) : ILogger
    {
        public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;

        public bool IsEnabled(LogLevel level) => true;

        public void Log<TState>(LogLevel level, EventId id, TState state, Exception? error, Func<TState, Exception?, string> formatter)
        {
            Console.WriteLine($"{level} {category}[{id.Id}]: {formatter(state, error)}");
            if (state is IReadOnlyList<KeyValuePair<string, object?>> values)
                Console.WriteLine($"  values: {string.Join(", ", values.Select(v => $"{v.Key} = {v.Value}"))}");
        }
    }
}
Building generated, and reading what the generators wrote Python · generated_session.py
from session import run

# generated uses four generators of .NET: JSON, regular expressions, logging and options validation. Its project sets
# EmitCompilerGeneratedFiles, so the build keeps a copy of every generated file under obj/. The third command lists
# them, the fourth shows the logging method that the generator wrote.
run("""
cd generated
dotnet build -v q > build.log
find obj/Debug/net10.0/generated -type f | sort
cat obj/Debug/net10.0/generated/Microsoft.Extensions.Logging.Generators/Microsoft.Extensions.Logging.Generators.LoggerMessageGenerator/LoggerMessage.g.cs
dotnet run --no-build
""")

Output

$ cd generated
$ dotnet build -v q > build.log
$ find obj/Debug/net10.0/generated -type f | sort
obj/Debug/net10.0/generated/Microsoft.AspNetCore.App.SourceGenerators/Microsoft.AspNetCore.SourceGenerators.PublicProgramSourceGenerator/PublicTopLevelProgram.Generated.g.cs
obj/Debug/net10.0/generated/Microsoft.Extensions.Logging.Generators/Microsoft.Extensions.Logging.Generators.LoggerMessageGenerator/LoggerMessage.g.cs
obj/Debug/net10.0/generated/Microsoft.Extensions.Options.SourceGeneration/Microsoft.Extensions.Options.Generators.OptionsValidatorGenerator/Validators.g.cs
obj/Debug/net10.0/generated/System.Text.Json.SourceGeneration/System.Text.Json.SourceGeneration.JsonSourceGenerator/BookingJson.Booking.g.cs
obj/Debug/net10.0/generated/System.Text.Json.SourceGeneration/System.Text.Json.SourceGeneration.JsonSourceGenerator/BookingJson.g.cs
obj/Debug/net10.0/generated/System.Text.Json.SourceGeneration/System.Text.Json.SourceGeneration.JsonSourceGenerator/BookingJson.GetJsonTypeInfo.g.cs
obj/Debug/net10.0/generated/System.Text.Json.SourceGeneration/System.Text.Json.SourceGeneration.JsonSourceGenerator/BookingJson.Int32.g.cs
obj/Debug/net10.0/generated/System.Text.Json.SourceGeneration/System.Text.Json.SourceGeneration.JsonSourceGenerator/BookingJson.PropertyNames.g.cs
obj/Debug/net10.0/generated/System.Text.Json.SourceGeneration/System.Text.Json.SourceGeneration.JsonSourceGenerator/BookingJson.String.g.cs
obj/Debug/net10.0/generated/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs
$ cat obj/Debug/net10.0/generated/Microsoft.Extensions.Logging.Generators/Microsoft.Extensions.Logging.Generators.LoggerMessageGenerator/LoggerMessage.g.cs
// <auto-generated/>
#nullable enable

    partial class Log
    {
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "10.0.14.42308")]
        private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, global::System.String, global::System.Int32, global::System.Exception?> __BookedCallback =
            global::Microsoft.Extensions.Logging.LoggerMessage.Define<global::System.String, global::System.Int32>(global::Microsoft.Extensions.Logging.LogLevel.Information, new global::Microsoft.Extensions.Logging.EventId(1, nameof(Booked)), "Booked {Pnr} for {Passengers} passengers", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true });

        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "10.0.14.42308")]
        public static partial void Booked(global::Microsoft.Extensions.Logging.ILogger logger, global::System.String pnr, global::System.Int32 passengers)
        {
            if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Information))
            {
                __BookedCallback(logger, pnr, passengers, null);
            }
        }
    }
$ dotnet run --no-build
{"pnr":"4521873690","passengers":2}
PNR well formed: True
Information Bookings[1]: Booked 4521873690 for 2 passengers
  values: Pnr = 4521873690, Passengers = 2, {OriginalFormat} = Booked {Pnr} for {Passengers} passengers
options valid: False; MaxPassengers: The field BookingLimits.MaxPassengers must be between 1 and 6.

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 generated_session.py

The JSON generator wrote six files, among them one for each type it handles, Booking, Int32 and String; the regex, logging and options generators one each; and ASP.NET Core’s shared framework added a tenth, a public partial Program class for top-level programs. The logging file is short enough to read whole: Booked first asks logger.IsEnabled, and only then calls a delegate built once by LoggerMessage.Define. The run shows the structured values a logging provider receives, with the template under {OriginalFormat}.

Key idea

A generator turns an attribute on a partial declaration into ordinary C# in your build: you can read it under obj/, step into it in a debugger, and it runs without reflection.

Checkpoint

Check: Reading the code a generator writes

  1. Question 1 of 2 A project sets EmitCompilerGeneratedFiles to true. Where did the build put the generated files of the project generated?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Under obj/Debug/net10.0/generated, in a folder per generator

    The copies are for reading and debugging; the compiler uses the generated source either way.

  2. Question 2 of 2 What did the generated Booked method do before it logged anything?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It asked logger.IsEnabled for the Information level

    Checking the level first is what lets a disabled log call do almost no work.

Generated code against reflection, with the warnings and bytes measured Pro: opens with a Pro, Premium or Ultimate pass

Moving work from run time to build time has two measurable payoffs: trim and AOT warnings that disappear, and allocations that vanish from hot paths. This part measures both.

In this part:

  • JSON and configuration: six AOT warnings, then none
  • LoggerMessage logs without allocating, measured

4 runnable examples (C#, Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Options validation and LibraryImport, and the code they write Pro: opens with a Pro, Premium or Ultimate pass

Two more generators replace reflection and run-time code with code you can read: the options validator, which reads validation attributes during the build, and LibraryImport, which writes the marshalling of native calls.

In this part:

  • The options validator turns attributes into code, once
  • LibraryImport writes the marshalling, and asks for unsafe code

3 runnable examples (C#, Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Diagnosing generators, and a lab that moves an app to generated code Pro: opens with a Pro, Premium or Ultimate pass

When a generator cannot do its job it says so with a SYSLIB diagnostic, and the build often shows a second, more confusing error next to it. This part reads the most common pairs and ends with a lab.

In this part:

  • Five mistakes, and the error that each one brings with it
  • Lab: move an app to generated code

3 runnable examples (C#, Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise

Practice that adapts to you

Practise this lesson

10 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 10 When does a source generator run?

    Choose one answer.

    Show the answer: Question 1 of 10

    Answer: While the project is compiled, inside the compiler

    That is why generated code needs no reflection: the work of looking at your types was done during the build.

  2. Question 2 of 10 You want structured logging without boxing or formatting when a level is off. What do you write?

    Choose one answer.

    Show the answer: Question 2 of 10

    Answer: A static partial method with [LoggerMessage], its level and its template

    Each generator answers its own attribute, or for configuration binding a project setting: the table of the lesson lists six.

  3. Question 3 of 10 In regex.cs, what is the generated Codes.Ifsc, compared with new Regex(...)?

    Choose one answer.

    Show the answer: Question 3 of 10

    Answer: An object of a class derived from Regex that the generator wrote, the same object on every read

    The generated class contains the matching code itself, so nothing is parsed or compiled when the program runs.

  4. Question 4 of 10 A Native AOT console tool validates IFSC codes with new Regex(pattern) inside a loop over 100,000 rows. What do you change, and why?

    Choose one answer.

    Show the answer: Question 4 of 10

    Answer: Declare the pattern once as a [GeneratedRegex] partial property, so it is generated code made once

    Moving work to build time is the point of every generator in this lesson.

  5. Question 5 of 10 Why do generators need partial members?

    Choose one answer.

    Show the answer: Question 5 of 10

    Answer: They can only add code, so you declare the member and they write its implementing part

    A partial type can be spread over files, and a partial member over its declaring and implementing parts.

  6. Question 6 of 10 You declare public partial string Describe(); and nothing implements it. What happens?

    Choose one answer.

    Show the answer: Question 6 of 10

    Answer: A compile error: a partial method with an access modifier or a return value must be implemented

    This is the contract generators rely on: a public partial member must be completed, by you or by them.

  7. Question 7 of 10 What must the implementing declaration of a partial event contain?

    Choose one answer.

    Show the answer: Question 7 of 10

    Answer: Its add and remove accessors

    Partial constructors and events arrived with C# 14; partial properties and indexers with C# 13.

  8. Question 8 of 10 Which MSBuild property keeps a copy of every generated file on disk?

    Choose one answer.

    Show the answer: Question 8 of 10

    Answer: EmitCompilerGeneratedFiles

    With the copies on disk, generated code can be read, searched and compared between builds.

  9. Question 9 of 10 The project generated used four generators of .NET. How many files did the JSON generator write for one context with one record?

    Choose one answer.

    Show the answer: Question 9 of 10

    Answer: Six, including one for each type it handles: Booking, Int32 and String

    Each type the context needs, including the int and string of the record's properties, gets its metadata in a file.

  10. Question 10 of 10 A [LoggerMessage] method never writes anything in production. What is the quickest way to see why?

    Choose one answer.

    Show the answer: Question 10 of 10

    Answer: Read or step into the generated method: it logs only if logger.IsEnabled is true for its level

    Generated code is ordinary code: reading it answers most questions about what a generator does.

Regex Tester Try a pattern on sample text before you put it in a [GeneratedRegex] attribute.

Interview questions

Fresher · What does a source generator do, and what can it not do?

It runs inside the compiler during a build, reads the compiler’s model of your code and adds new source files to the compilation. It cannot change or remove code you wrote, which is why generated code fills in partial members.

  1. Mid to senior

    A profiler shows 64 bytes allocated by every logger.LogInformation call in a hot loop, although Information is switched off in production. Why does a disabled log call allocate, and how do you remove the cost without losing the log line?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    After adding a JsonSerializerContext and a [GeneratedRegex] property, a build fails with CS0534 on the context and CS9248 on the property, among other errors. A teammate wants to go back to reflection and new Regex(...). What do you check first, and how do you fix it?

    Model answer, Pro. First step and follow-ups

  3. Senior to staff

    Your team must publish a console service with Native AOT. It serialises JSON by reflection, binds configuration with Get<T>, builds regexes at run time, logs with LogInformation and calls one native library with DllImport. Plan the move to generated code, and say how you will know it is finished.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A source generator runs while the project builds, reads the compilation and adds source files, and it never changes code you wrote.
  • Partial members split a member into a declaration and an implementation, which is how your code and a generator share one type; a partial method that may stay unimplemented, and is, disappears with its calls.
  • EmitCompilerGeneratedFiles keeps every generated file under obj/, so generated code can be read and debugged like your own.

Terms in this lesson

partial member
A method, property, indexer, constructor or event declared in one part of a partial type and implemented in another, often by a source generator. Only a private void method may be left without an implementation.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.