<PackageReference Include="System.Text.Json" Version="7.0.0" />

JsonConverter<T>

public abstract class JsonConverter<T> : JsonConverter
Converts an object or value to or from JSON.
using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.Json.Serialization.Converters; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public abstract class JsonConverter<[System.Runtime.CompilerServices.Nullable(2)] T> : JsonConverter { internal override ConverterStrategy ConverterStrategy => ConverterStrategy.Value; [System.Runtime.CompilerServices.Nullable(2)] internal virtual JsonConverter SourceConverterForCastingConverter { get { return null; } } [System.Runtime.CompilerServices.Nullable(2)] internal override Type KeyType { get { return null; } } [System.Runtime.CompilerServices.Nullable(2)] internal override Type ElementType { get { return null; } } public virtual bool HandleNull { get { HandleNullOnRead = (default(T) != null); HandleNullOnWrite = false; return false; } } internal bool HandleNullOnRead { get; set; } internal bool HandleNullOnWrite { get; set; } internal sealed override Type TypeToConvert { get; } = typeof(T); internal sealed override object ReadCoreAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state) { return ReadCore(ref reader, options, ref state); } internal T ReadCore(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state) { try { if (!state.IsContinuation) { if (!JsonConverter.SingleValueReadWithReadAhead(base.RequiresReadAhead, ref reader, ref state)) { if (!state.SupportContinuation) { state.BytesConsumed += reader.BytesConsumed; return default(T); } state.BytesConsumed += reader.BytesConsumed; if (state.Current.ReturnValue != null) return (T)state.Current.ReturnValue; return default(T); } } else if (!JsonConverter.SingleValueReadWithReadAhead(true, ref reader, ref state)) { state.BytesConsumed += reader.BytesConsumed; return default(T); } if (TryRead(ref reader, TypeToConvert, options, ref state, out T value) && !reader.Read() && !reader.IsFinalBlock) state.Current.ReturnValue = value; state.BytesConsumed += reader.BytesConsumed; return value; } catch (JsonReaderException ex) { ThrowHelper.ReThrowWithPath(ref state, ex); return default(T); } catch (FormatException ex2) when (ex2.Source == "System.Text.Json.Rethrowable") { ThrowHelper.ReThrowWithPath(ref state, ref reader, ex2); return default(T); } catch (InvalidOperationException ex3) when (ex3.Source == "System.Text.Json.Rethrowable") { ThrowHelper.ReThrowWithPath(ref state, ref reader, ex3); return default(T); } catch (JsonException ex4) when (ex4.Path == null) { ThrowHelper.AddJsonExceptionInformation(ref state, ref reader, ex4); throw; } catch (NotSupportedException ex5) { if (ex5.Message.Contains(" Path: ")) throw; ThrowHelper.ThrowNotSupportedException(ref state, ref reader, ex5); return default(T); } } internal sealed override bool WriteCoreAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state) { if (base.IsValueType) { if (default(T) != null && value == null) ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.IgnoreCycles && value != null) state.ReferenceResolver.PushReferenceForCycleDetection(value); } T value2 = (T)value; return WriteCore(writer, ref value2, options, ref state); } internal bool WriteCore(Utf8JsonWriter writer, [In] [System.Runtime.CompilerServices.IsReadOnly] ref T value, JsonSerializerOptions options, ref WriteStack state) { try { return TryWrite(writer, ref value, options, ref state); } catch (InvalidOperationException ex) when (ex.Source == "System.Text.Json.Rethrowable") { ThrowHelper.ReThrowWithPath(ref state, ex); throw; } catch (JsonException ex2) when (ex2.Path == null) { ThrowHelper.AddJsonExceptionInformation(ref state, ex2); throw; } catch (NotSupportedException ex3) { if (ex3.Message.Contains(" Path: ")) throw; ThrowHelper.ThrowNotSupportedException(ref state, ex3); return false; } } protected internal JsonConverter() : this(true) { } internal JsonConverter(bool initialize) { base.IsValueType = typeof(T).IsValueType; base.IsInternalConverter = (GetType().Assembly == typeof(JsonConverter).Assembly); if (initialize) Initialize(); } private protected void Initialize() { if (HandleNull) { HandleNullOnRead = true; HandleNullOnWrite = true; } base.CanUseDirectReadOrWrite = (ConverterStrategy == ConverterStrategy.Value && base.IsInternalConverter); base.RequiresReadAhead = (ConverterStrategy == ConverterStrategy.Value); } public override bool CanConvert(Type typeToConvert) { return typeToConvert == typeof(T); } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")] [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] internal sealed override JsonTypeInfo CreateReflectionJsonTypeInfo(JsonSerializerOptions options) { return new ReflectionJsonTypeInfo<T>(this, options); } internal sealed override JsonTypeInfo CreateCustomJsonTypeInfo(JsonSerializerOptions options) { return new CustomJsonTypeInfo<T>(this, options); } internal sealed override JsonParameterInfo CreateJsonParameterInfo() { return new JsonParameterInfo<T>(); } internal sealed override JsonConverter<TTarget> CreateCastingConverter<TTarget>() { JsonConverter<TTarget> jsonConverter = this as JsonConverter<TTarget>; if (jsonConverter != null) return jsonConverter; JsonSerializerOptions.CheckConverterNullabilityIsSameAsPropertyType(this, typeof(TTarget)); return this.SourceConverterForCastingConverter?.CreateCastingConverter<TTarget>() ?? new CastingConverter<TTarget, T>(this); } internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state) { T value2 = (T)value; return TryWrite(writer, ref value2, options, ref state); } internal virtual bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) { Write(writer, value, options); return true; } internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out T value) { value = Read(ref reader, typeToConvert, options); return true; } [return: System.Runtime.CompilerServices.Nullable(2)] public abstract T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options); internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out T value) { if (reader.TokenType == JsonTokenType.Null && !HandleNullOnRead && !state.IsContinuation) { if (default(T) != null) ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); value = default(T); return true; } if (ConverterStrategy == ConverterStrategy.Value) { if (base.IsInternalConverter) { if (state.Current.NumberHandling.HasValue && IsInternalConverterForNumberType) value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options); else value = Read(ref reader, typeToConvert, options); } else { JsonTokenType tokenType = reader.TokenType; int currentDepth = reader.CurrentDepth; long bytesConsumed = reader.BytesConsumed; if (state.Current.NumberHandling.HasValue && IsInternalConverterForNumberType) value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options); else value = Read(ref reader, typeToConvert, options); VerifyRead(tokenType, currentDepth, bytesConsumed, true, ref reader); } return true; } bool isContinuation = state.IsContinuation; bool flag; if (base.CanBePolymorphic) { flag = OnTryRead(ref reader, typeToConvert, options, ref state, out value); return true; } state.Push(); flag = OnTryRead(ref reader, typeToConvert, options, ref state, out value); state.Pop(flag); return flag; } internal sealed override bool OnTryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out object value) { T value2; bool result = OnTryRead(ref reader, TypeToConvert, options, ref state, out value2); value = value2; return result; } internal sealed override bool TryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out object value) { T value2; bool result = TryRead(ref reader, TypeToConvert, options, ref state, out value2); value = value2; return result; } private static bool IsNull(T value) { return value == null; } internal bool TryWrite(Utf8JsonWriter writer, [In] [System.Runtime.CompilerServices.IsReadOnly] ref T value, JsonSerializerOptions options, ref WriteStack state) { if (writer.CurrentDepth >= options.EffectiveMaxDepth) ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth); if (default(T) == null && !HandleNullOnWrite && IsNull(value)) { writer.WriteNullValue(); return true; } if (ConverterStrategy == ConverterStrategy.Value) { int currentDepth = writer.CurrentDepth; if (state.Current.NumberHandling.HasValue && IsInternalConverterForNumberType) WriteNumberWithCustomHandling(writer, value, state.Current.NumberHandling.Value); else Write(writer, value, options); VerifyWrite(currentDepth, writer); return true; } bool isContinuation = state.IsContinuation; bool flag; if (!base.IsValueType && value != null && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted) { JsonTypeInfo jsonTypeInfo = state.PeekNestedJsonTypeInfo(); JsonConverter jsonConverter = (base.CanBePolymorphic || jsonTypeInfo.PolymorphicTypeResolver != null) ? ResolvePolymorphicConverter(value, jsonTypeInfo, options, ref state) : null; if (!isContinuation && options.ReferenceHandlingStrategy != 0 && TryHandleSerializedObjectReference(writer, value, options, jsonConverter, ref state)) return true; if (jsonConverter != null) { flag = jsonConverter.TryWriteAsObject(writer, value, options, ref state); state.Current.ExitPolymorphicConverter(flag); if (flag && state.Current.IsPushedReferenceForCycleDetection) { state.ReferenceResolver.PopReferenceForCycleDetection(); state.Current.IsPushedReferenceForCycleDetection = false; } return flag; } } state.Push(); flag = OnTryWrite(writer, value, options, ref state); state.Pop(flag); if (flag && state.Current.IsPushedReferenceForCycleDetection) { state.ReferenceResolver.PopReferenceForCycleDetection(); state.Current.IsPushedReferenceForCycleDetection = false; } return flag; } internal bool TryWriteDataExtensionProperty(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) { if (!base.IsInternalConverter) return TryWrite(writer, ref value, options, ref state); object obj = this as JsonDictionaryConverter<T>; if (obj == null) { JsonMetadataServicesConverter<T> obj2 = this as JsonMetadataServicesConverter<T>; obj = (((obj2 != null) ? obj2.Converter : null) as JsonDictionaryConverter<T>); } JsonDictionaryConverter<T> jsonDictionaryConverter = (JsonDictionaryConverter<T>)obj; if (jsonDictionaryConverter == null) return TryWrite(writer, ref value, options, ref state); if (writer.CurrentDepth >= options.EffectiveMaxDepth) ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth); bool isContinuation = state.IsContinuation; state.Push(); if (!isContinuation) state.Current.OriginalDepth = writer.CurrentDepth; state.Current.IsWritingExtensionDataProperty = true; state.Current.JsonPropertyInfo = state.Current.JsonTypeInfo.ElementTypeInfo.PropertyInfoForTypeInfo; bool flag = jsonDictionaryConverter.OnWriteResume(writer, value, options, ref state); if (flag) VerifyWrite(state.Current.OriginalDepth, writer); state.Pop(flag); return flag; } internal void VerifyRead(JsonTokenType tokenType, int depth, long bytesConsumed, bool isValueConverter, ref Utf8JsonReader reader) { switch (tokenType) { case JsonTokenType.StartArray: if (reader.TokenType != JsonTokenType.EndArray) ThrowHelper.ThrowJsonException_SerializationConverterRead(this); else if (depth != reader.CurrentDepth) { ThrowHelper.ThrowJsonException_SerializationConverterRead(this); } break; case JsonTokenType.StartObject: if (reader.TokenType != JsonTokenType.EndObject) ThrowHelper.ThrowJsonException_SerializationConverterRead(this); else if (depth != reader.CurrentDepth) { ThrowHelper.ThrowJsonException_SerializationConverterRead(this); } break; default: if (isValueConverter) { if (reader.BytesConsumed != bytesConsumed) ThrowHelper.ThrowJsonException_SerializationConverterRead(this); } else if (!base.CanBePolymorphic && (!HandleNullOnRead || tokenType != JsonTokenType.Null)) { ThrowHelper.ThrowJsonException_SerializationConverterRead(this); } break; } } internal void VerifyWrite(int originalDepth, Utf8JsonWriter writer) { if (originalDepth != writer.CurrentDepth) ThrowHelper.ThrowJsonException_SerializationConverterWrite(this); } public abstract void Write(Utf8JsonWriter writer, [System.Runtime.CompilerServices.Nullable(0)] T value, JsonSerializerOptions options); public virtual T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (!base.IsInternalConverter && options.SerializerContext == null && DefaultJsonTypeInfoResolver.TryGetDefaultSimpleConverter(TypeToConvert, out JsonConverter converter)) return ((JsonConverter<T>)converter).ReadAsPropertyNameCore(ref reader, TypeToConvert, options); ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(TypeToConvert, this); return default(T); } internal virtual T ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { long bytesConsumed = reader.BytesConsumed; T result = ReadAsPropertyName(ref reader, typeToConvert, options); if (reader.BytesConsumed != bytesConsumed) ThrowHelper.ThrowJsonException_SerializationConverterRead(this); return result; } public virtual void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { if (!base.IsInternalConverter && options.SerializerContext == null && DefaultJsonTypeInfoResolver.TryGetDefaultSimpleConverter(TypeToConvert, out JsonConverter converter)) ((JsonConverter<T>)converter).WriteAsPropertyNameCore(writer, value, options, false); else ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(TypeToConvert, this); } internal virtual void WriteAsPropertyNameCore(Utf8JsonWriter writer, T value, JsonSerializerOptions options, bool isWritingExtensionDataProperty) { if (isWritingExtensionDataProperty) writer.WritePropertyName((string)(object)value); else { int currentDepth = writer.CurrentDepth; WriteAsPropertyName(writer, value, options); if (currentDepth != writer.CurrentDepth || writer.TokenType != JsonTokenType.PropertyName) ThrowHelper.ThrowJsonException_SerializationConverterWrite(this); } } internal sealed override void WriteAsPropertyNameCoreAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, bool isWritingExtensionDataProperty) { WriteAsPropertyNameCore(writer, (T)value, options, isWritingExtensionDataProperty); } internal virtual T ReadNumberWithCustomHandling(ref Utf8JsonReader reader, JsonNumberHandling handling, JsonSerializerOptions options) { throw new InvalidOperationException(); } internal virtual void WriteNumberWithCustomHandling(Utf8JsonWriter writer, T value, JsonNumberHandling handling) { throw new InvalidOperationException(); } } }