Start Debugging
2026-05-01 Aktualisiert 2026-11-02 csharpdotnetdotnet-8 Edit on GitHub

.NET 8 JsonSerializerOptions als readonly markieren

JsonSerializerOptions mit MakeReadOnly einfrieren, den fehlenden TypeInfoResolver ergänzen und eine veränderbare Kopie erstellen: ausführbares .NET-8-Beispiel.

Diese Website nutzt Walter, einen KI-Agenten, für Recherche, Texte und Pflege. Redaktion und Überprüfung

Ab .NET 8 friert JsonSerializerOptions.MakeReadOnly() eine Optionsinstanz ein. Konfigurieren Sie vorher deren TypeInfoResolver: Ein neues Optionsobjekt hat keinen Resolver, daher wirft der sofortige Aufruf der parameterlosen Methode InvalidOperationException.

Korrektur — 2. November 2026: Im vorherigen Beispiel fehlte der Resolver, weshalb es bereits bei MakeReadOnly() scheiterte. Das folgende Beispiel verwendet generierte Metadaten und funktioniert auch mit deaktivierten Reflection-Standardwerten.

Konfigurierte Optionen einfrieren

Diese vollständige Program.cs verwendet einen generierten Resolver, serialisiert mit eingefrorenen Optionen, weist eine spätere Änderung zurück und erstellt eine unabhängig konfigurierbare Kopie:

using System.Text.Json;
using System.Text.Json.Serialization;

var options = new JsonSerializerOptions
{
    TypeInfoResolver = DemoJsonContext.Default,
    PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseUpper
};
options.MakeReadOnly();
Console.WriteLine(options.IsReadOnly);
Console.WriteLine(JsonSerializer.Serialize(new Widget(42, "Ada"), options));

try
{
    options.WriteIndented = true;
}
catch (InvalidOperationException)
{
    Console.WriteLine("Mutation rejected");
}

var copy = new JsonSerializerOptions(options);
Console.WriteLine(copy.IsReadOnly);
copy.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
Console.WriteLine(JsonSerializer.Serialize(new Widget(42, "Ada"), copy));

public sealed record Widget(int Id, string Name);

[JsonSerializable(typeof(Widget))]
internal partial class DemoJsonContext : JsonSerializerContext { }

Ausgabe:

True
{"ID":42,"NAME":"Ada"}
Mutation rejected
False
{"id":42,"name":"Ada"}

Nach dem Einfrieren ist IsReadOnly gleich true. Ein erneuter Aufruf von MakeReadOnly() ist zulässig. Eine spätere Änderung einer Einstellung wirft InvalidOperationException. Auch Serialisierung oder Deserialisierung macht eine Optionsinstanz schreibgeschützt.

Der Kopierkonstruktor übernimmt die Einstellungen einschließlich Resolver, erstellt aber eine veränderbare Instanz. Konfigurieren Sie die Kopie vor der ersten Verwendung; auch sie wird beim Serialisieren eingefroren.

Warum wirft MakeReadOnly ohne Resolver eine Ausnahme?

new JsonSerializerOptions().MakeReadOnly() wählt keinen Resolver automatisch aus. Geben Sie ihn wie oben ausdrücklich an, oder verwenden Sie MakeReadOnly(populateMissingResolver: true), wenn Reflection-Serialisierung beabsichtigt und aktiviert ist.

Diese Überladung ergänzt einen fehlenden Resolver durch den Reflection-Standardresolver. Sind die Reflection-Standardwerte deaktiviert, kann sie die Lücke nicht schließen und wirft InvalidOperationException. Für getrimmte oder Native-AOT-Anwendungen ersetzt sie keine generierten Metadaten. Siehe Reflection-Standardwerte deaktivieren und einen Kontext konfigurieren sowie den MakeReadOnly-API-Vertrag.

Das geprüfte Beispiel ausführen

Laden Sie das vollständige System.Text.Json-Optionsprojekt herunter, entpacken Sie es und führen Sie Folgendes aus:

dotnet run -c Release

Das .NET-8-Projekt ohne zusätzliche Abhängigkeiten prüft fehlende Resolver, wiederholtes Einfrieren, zurückgewiesene Änderungen, generierte Serialisierung und Kopierverhalten. Es prüft populateMissingResolver getrennt mit deaktivierten und aktivierten Reflection-Standardwerten. Alle Prüfungen bestanden auf den tatsächlichen Runtimes .NET 8.0.33 und .NET 10.0.10; Befehle und Ergebnisse stehen im Prüfprotokoll des Archivs.

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.