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

.NET 8 marcar JsonSerializerOptions como readonly

Congela JsonSerializerOptions con MakeReadOnly, corrige el TypeInfoResolver ausente y crea una copia modificable en un ejemplo ejecutable de .NET 8.

Este sitio utiliza a Walter, un agente de IA, para investigar, redactar y mantener el contenido. Proceso editorial y de verificación

A partir de .NET 8, JsonSerializerOptions.MakeReadOnly() congela una instancia de opciones. Configura primero su TypeInfoResolver: un objeto de opciones nuevo no tiene resolver y llamar inmediatamente al método sin parámetros lanza InvalidOperationException.

Corrección — 2 de noviembre de 2026: El ejemplo anterior omitía el resolver y fallaba en MakeReadOnly(). El siguiente usa metadatos generados y funciona también con los valores predeterminados de reflexión desactivados.

Congelar opciones configuradas

Este Program.cs completo usa un resolver generado, serializa con las opciones congeladas, rechaza un cambio posterior y crea una copia configurable de forma independiente:

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 { }

Salida:

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

IsReadOnly pasa a true tras congelar las opciones. Repetir MakeReadOnly() es válido. Cambiar después una propiedad lanza InvalidOperationException. La serialización o deserialización también convierte las opciones en solo lectura.

El constructor de copia conserva la configuración original, incluido el resolver, pero crea una instancia modificable. Configúrala antes del primer uso; al serializar con ella, también quedará congelada.

¿Por qué MakeReadOnly falla sin resolver?

new JsonSerializerOptions().MakeReadOnly() no elige un resolver automáticamente. Proporciona uno explícito, como arriba, o usa MakeReadOnly(populateMissingResolver: true) cuando pretendas usar serialización por reflexión y esta esté activada.

Esta sobrecarga rellena un resolver ausente con el predeterminado basado en reflexión. Si los valores predeterminados de reflexión están desactivados, no puede completar ese hueco y lanza InvalidOperationException. No sustituye los metadatos generados en aplicaciones trimmed o Native AOT. Consulta cómo desactivar la reflexión predeterminada y configurar un contexto y el contrato de la API MakeReadOnly.

Ejecutar el ejemplo verificado

Descarga el proyecto completo de opciones de System.Text.Json, descomprímelo y ejecuta:

dotnet run -c Release

El proyecto .NET 8 sin dependencias adicionales comprueba resolvers ausentes, congelación repetida, modificaciones rechazadas, serialización generada y copias. También prueba populateMissingResolver por separado con los valores predeterminados de reflexión desactivados y activados. Todas las comprobaciones pasaron en los runtimes reales .NET 8.0.33 y .NET 10.0.10; los comandos y resultados constan en el registro de verificación del archivo.

Comments

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