Serialización polimórfica de tipos de objeto

Con la configuración predeterminada, System.Text.Json serializa los valores de tipo objectmediante polimorfismo. Este comportamiento es menos coherente si se registra un convertidor personalizado para object. Históricamente, System.Text.Json ha codificado de forma rígida el polimorfismo de los valores de objeto de nivel raíz, pero no de los valores de objeto anidados. A partir de .NET 7, este comportamiento ha cambiado para que los convertidores personalizados no usen nunca polimorfismo.

Comportamiento anterior

Veamos el siguiente convertidor de objetos personalizado:

public class CustomObjectConverter : JsonConverter<object>
{
    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
        => writer.WriteNumberValue(42);

    public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => throw new NotImplementedException();
}

En versiones anteriores, el código siguiente se serializaba como 0. Esto se debe a que el serializador usaba polimorfismo y omitía el convertidor personalizado.

var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } };
JsonSerializer.Serialize<object>(0, options);

Sin embargo, el siguiente código se serializaba como 42 porque el serializador respetaba el convertidor personalizado.

var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } };
JsonSerializer.Serialize<object[]>(new object[] { 0 }, options);

Comportamiento nuevo

A partir de .NET 7, al usar el convertidor de objetos personalizado definido en la sección Comportamiento anterior, el código siguiente se serializa como 42. Esto se debe a que el serializador siempre consultará al convertidor personalizado, y no usará polimorfismo.

var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } };
JsonSerializer.Serialize<object>(0, options);

Versión introducida

.NET 7

Tipo de cambio importante

Este cambio puede afectar a la compatibilidad binaria.

Motivo del cambio

Este cambio se ha realizado debido a que los contratos de serialización de un tipo eran incoherentes, según si este se serializaba como un valor de nivel raíz o como un valor anidado.

Si lo desea, puede recuperar el uso del polimorfismo con los valores de nivel raíz, invocando para ello uno de los métodos de serialización sin tipo:

var options = new JsonSerializerOptions { Converters = { new CustomObjectConverter() } };
JsonSerializer.Serialize(0, inputType: typeof(int), options); // Serializes as 0.

API afectadas