<PackageReference Include="NJsonSchema" Version="11.0.0-preview006" />

JsonInheritanceConverter<TBase>

public class JsonInheritanceConverter<TBase> : JsonConverter<TBase>
Defines the class as inheritance base class and adds a discriminator property to the serialized object.
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; namespace NJsonSchema.Converters { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 2 })] public class JsonInheritanceConverter<[System.Runtime.CompilerServices.Nullable(2)] TBase> : JsonConverter<TBase> { private readonly string _discriminatorName; public static IDictionary<string, Type> AdditionalKnownTypes { get; } = new Dictionary<string, Type>(); public virtual string DiscriminatorName => _discriminatorName; public JsonInheritanceConverter() { _discriminatorName = (CustomAttributeExtensions.GetCustomAttribute<JsonInheritanceConverterAttribute>((MemberInfo)typeof(TBase))?.DiscriminatorName ?? "discriminator"); } public JsonInheritanceConverter(string discriminatorName) { _discriminatorName = discriminatorName; } [return: System.Runtime.CompilerServices.Nullable(2)] public override TBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader); JsonElement rootElement = jsonDocument.RootElement; JsonElement value; bool flag = rootElement.TryGetProperty(_discriminatorName, out value); Type discriminatorType = GetDiscriminatorType(jsonDocument.RootElement, typeToConvert, flag ? value.GetString() : null); MemoryStream memoryStream = new MemoryStream(); using (Utf8JsonWriter writer = new Utf8JsonWriter(memoryStream, default(JsonWriterOptions))) { rootElement = jsonDocument.RootElement; rootElement.WriteTo(writer); } return (TBase)JsonSerializer.Deserialize(memoryStream.ToArray(), discriminatorType, options); } public override void Write(Utf8JsonWriter writer, [System.Runtime.CompilerServices.Nullable(2)] TBase value, JsonSerializerOptions options) { if (value != null) { writer.WriteStartObject(); writer.WriteString(_discriminatorName, GetDiscriminatorValue(value.GetType())); byte[] array = JsonSerializer.SerializeToUtf8Bytes<object>((object)value, options); JsonDocument jsonDocument = JsonDocument.Parse(array, default(JsonDocumentOptions)); foreach (JsonProperty item in jsonDocument.RootElement.EnumerateObject()) { item.WriteTo(writer); } writer.WriteEndObject(); } else writer.WriteNullValue(); } public virtual string GetDiscriminatorValue(Type type) { KeyValuePair<string, Type> keyValuePair = Enumerable.SingleOrDefault<KeyValuePair<string, Type>>((IEnumerable<KeyValuePair<string, Type>>)AdditionalKnownTypes, (Func<KeyValuePair<string, Type>, bool>)((KeyValuePair<string, Type> p) => p.Value == type)); if (keyValuePair.Key != null) return keyValuePair.Key; string subtypeDiscriminator = GetSubtypeDiscriminator(type); if (subtypeDiscriminator != null) return subtypeDiscriminator; return type.Name; } protected virtual Type GetDiscriminatorType(JsonElement jObject, Type objectType, [System.Runtime.CompilerServices.Nullable(2)] string discriminatorValue) { if (discriminatorValue != null) { if (AdditionalKnownTypes.ContainsKey(discriminatorValue)) return AdditionalKnownTypes[discriminatorValue]; Type objectSubtype = GetObjectSubtype(objectType, discriminatorValue); if (objectSubtype != (Type)null) return objectSubtype; if (objectType.Name == discriminatorValue) return objectType; Type subtypeFromKnownTypeAttributes = GetSubtypeFromKnownTypeAttributes(objectType, discriminatorValue); if (subtypeFromKnownTypeAttributes != (Type)null) return subtypeFromKnownTypeAttributes; string name = objectType.Namespace + "." + discriminatorValue; Type type = objectType.GetTypeInfo().Assembly.GetType(name); if (type != (Type)null) return type; } throw new InvalidOperationException("Could not find subtype of '" + objectType.Name + "' with discriminator '" + discriminatorValue + "'."); } [return: System.Runtime.CompilerServices.Nullable(2)] private static Type GetSubtypeFromKnownTypeAttributes(Type objectType, string discriminatorValue) { Type type = objectType; do { IEnumerable<object> enumerable = Enumerable.Where<object>((IEnumerable<object>)type.GetTypeInfo().GetCustomAttributes(false), (Func<object, bool>)((object a) => a.GetType().Name == "KnownTypeAttribute")); foreach (dynamic item in enumerable) { dynamic val = item.Type != null; if ((val ? false : true) ? val : (val & (item.Type.Name == discriminatorValue))) return (Type)item.Type; if (item.MethodName != null) { MethodInfo runtimeMethod = type.GetRuntimeMethod((string)item.MethodName, new Type[0]); if (runtimeMethod != (MethodInfo)null) { IEnumerable<Type> enumerable2 = runtimeMethod.Invoke(null, new object[0]) as IEnumerable<Type>; if (enumerable2 != null) { foreach (Type item2 in enumerable2) { if (item2.Name == discriminatorValue) return item2; } } return null; } } } type = type.GetTypeInfo().BaseType; } while (type != (Type)null); return null; } [return: System.Runtime.CompilerServices.Nullable(2)] private static Type GetObjectSubtype(Type baseType, string discriminatorValue) { IEnumerable<JsonInheritanceAttribute> source = Enumerable.OfType<JsonInheritanceAttribute>((IEnumerable)baseType.GetTypeInfo().GetCustomAttributes(true)); return Enumerable.SingleOrDefault<JsonInheritanceAttribute>(source, (Func<JsonInheritanceAttribute, bool>)((JsonInheritanceAttribute a) => a.Key == discriminatorValue))?.Type; } [return: System.Runtime.CompilerServices.Nullable(2)] private static string GetSubtypeDiscriminator(Type objectType) { IEnumerable<JsonInheritanceAttribute> source = Enumerable.OfType<JsonInheritanceAttribute>((IEnumerable)objectType.GetTypeInfo().GetCustomAttributes(true)); return Enumerable.SingleOrDefault<JsonInheritanceAttribute>(source, (Func<JsonInheritanceAttribute, bool>)((JsonInheritanceAttribute a) => a.Type == objectType))?.Key; } } }