При попытке сериализовать список, в котором объекты являются производными типами универсального и универсального базового, я получаю ошибку:
System.InvalidOperationException: ' Указанный тип CSharpLanguageTestingApp.CustomResult1[T]' is not a supported derived type for the polymorphic type 'CSharpLanguageTestingApp.CustomResult1[CSharpLanguageTestingApp.AggregateTwo]'. Производные типы должны назначаться базовому типу, не должны быть универсальными и не могут быть абстрактными классами или интерфейсами, если не указан JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor.'
FallBackToNearestAncestor в настоящее время ничего не делает.
Пример класса:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace CSharpLanguageTestingApp
{
public class AggregateOne
{
int iAmAggregateOne { get; set; } = 1;
}
public class AggregateTwo
{
public int iAmAggregateTwo { get; set; } = 2;
}
[JsonPolymorphic]
[JsonDerivedType(typeof(CustomResult), "CustomResult")]
[JsonDerivedType(typeof(dbCustomResult), "dbCustomResult")]
[JsonDerivedType(typeof(sbCustomResult), "sbCustomResult")]
[JsonDerivedType(typeof(apiCustomResult), "apiCustomResult")]
public class CustomResult
{
public int iAmAResult { get; set; } = 0;
}
public class dbCustomResult : CustomResult
{
public int iAmADbResult { get; set; } = 0;
}
public class sbCustomResult : CustomResult
{
public int iAmASbResult { get; set; } = 0;
}
public class apiCustomResult : CustomResult
{
public int iAmAnApiResult { get; set; } = 0;
}
public class CompositeResult
{
public string Name { get; set; } = "CompositeResult";
[JsonConverter(typeof(PolymorphicListConverter))]
public List IndividualResults { get; set; } = new();
}
}
Конвертер:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
namespace CSharpLanguageTestingApp
{
public class PolymorphicListConverter : JsonConverter
{
public override List Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var results = new List();
// Ensure we're at the start of the array
if (reader.TokenType == JsonTokenType.StartArray)
{
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
{
if (reader.TokenType == JsonTokenType.StartObject)
{
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
{
JsonElement root = doc.RootElement;
if (root.TryGetProperty("$type", out JsonElement typeElement))
{
string typeName = typeElement.GetString();
Type type = Type.GetType(typeName);
if (type != null)
{
var json = root.GetProperty("Data").GetRawText();
var obj = JsonSerializer.Deserialize(json, type, options);
results.Add(obj);
}
}
}
}
}
}
return results;
}
public override void Write(Utf8JsonWriter writer, List value, JsonSerializerOptions options)
{
writer.WriteStartArray();
foreach (var result in value)
{
if (result != null)
{
try
{
// Get the runtime type of the object
var resultType = result.GetType();
writer.WriteStartObject();
writer.WriteString("$type", resultType.AssemblyQualifiedName);
writer.WritePropertyName("Data");
// Serialize the object as is
string json = "";
try
{
json = JsonSerializer.Serialize(result, options); // try 1
}
catch (Exception ex)
{
Console.WriteLine($"Error serializing object of type {result.GetType()}: {ex.Message}");
}
try
{
JsonSerializer.Serialize(writer, result, resultType, options); // try 2
}
catch (Exception ex)
{
Console.WriteLine($"Error serializing object of type {result.GetType()}: {ex.Message}");
}
writer.WriteEndObject();
}
catch (Exception ex)
{
Console.WriteLine($"Error serializing object of type {result.GetType()}: {ex.Message}");
throw; // Rethrow or handle the exception as needed
}
}
}
writer.WriteEndArray();
}
}
}
Программа для тестирования:
CompositeResult compositeResult = new CompositeResult();
compositeResult.IndividualResults.Add(new dbCustomResult());
compositeResult.IndividualResults.Add(new CustomResult());
compositeResult.IndividualResults.Add(new sbCustomResult());
compositeResult.IndividualResults.Add(new apiCustomResult());
var options = new JsonSerializerOptions();
options.Converters.Add(new PolymorphicListConverter());
string json = "";
try
{
json = System.Text.Json.JsonSerializer.Serialize(compositeResult, options);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine(json);
Пытался добавить конвертеры, но у меня есть множество агрегатов, чтобы упростить управление конвертерами параметров json. Пробовал модифицировать конвертер, но пока безуспешно.
Пока мне не удается добиться, чтобы универсальные производные и базовые типы хорошо работали в одном списке при сериализации/десериализации
Удаление CustomResult из списка работает:
{
"Name": "CompositeResult",
"IndividualResults": [
{
"$type": "CSharpLanguageTestingApp.dbCustomResult\u00601[[CSharpLanguageTestingApp.AggregateOne, CSharpLanguageTestingApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], CSharpLanguageTestingApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Data": { "iAmADbResult": 0, "iAmAResult": 0 }
},
{
"$type": "CSharpLanguageTestingApp.sbCustomResult\u00601[[CSharpLanguageTestingApp.AggregateTwo, CSharpLanguageTestingApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], CSharpLanguageTestingApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Data": { "iAmASbResult": 0, "iAmAResult": 0 }
},
{
"$type": "CSharpLanguageTestingApp.apiCustomResult\u00601[[CSharpLanguageTestingApp.AggregateOne, CSharpLanguageTestingApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], CSharpLanguageTestingApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Data": { "iAmAnApiResult": 0, "iAmAResult": 0 }
}
]
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... -sharp-net
(De) Сериализация списка объектов, содержащих полиморфные дженерики, в C# .NET 8 с помощью System.Text.Json ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение