Код: Выделить всё
internal class OrderItem
{
public string Name { get; set; }
public Order Order { get; set; }
}
internal class Order
{
public IReadOnlyList Items { get; set; }
}
internal class Container
{
public object[] values { get; set; }
}
Код: Выделить всё
ContainerЯ использую Newtonsoft.Json для сериализации, и следующий тест не пройден:
Код: Выделить всё
var order = new Order();
var orderItems = new List() {
new OrderItem() { Name = "One", Order = order },
new OrderItem() { Name = "Two", Order = order } };
order.Items = orderItems;
var container = new Container() { values = [order, orderItems] };
var settings = new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
TypeNameHandling = TypeNameHandling.Objects,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
};
var json = JsonConvert.SerializeObject(container, settings);
var restored = JsonConvert.DeserializeObject(json, settings);
Assert.AreEqual(typeof(Order), restored.values[0].GetType());
Assert.AreEqual(typeof(List), restored.values[1].GetType());
Код: Выделить всё
public class CustomListConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(object);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
//JArray -> List
if (token.Type == JTokenType.Array)
{
return token.ToObject(serializer);
}
else
{
//Removing CustomListConverter from serializer.Converters
var self = serializer.Converters.FirstOrDefault(c => ReferenceEquals(c, this));
bool removed = false;
if (self != null)
{
removed = serializer.Converters.Remove(self);
}
try
{
//and than deserialize (using default Newtonsoft.Json converters)
using (var subReader = token.CreateReader())
{
return serializer.Deserialize(subReader);
}
}
finally
{
//Restoring CustomListConverter if it was removed
if (removed && self != null)
{
serializer.Converters.Add(self);
}
}
}
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> throw new NotSupportedException("This converter is read-only.");
}
Код: Выделить всё
settings.Converters.Add(new ObjectToConcreteConverter());Я надеюсь, что необходим код, который удаляет CustomListConverter перед десериализацией и восстанавливает его после (чтобы избежать бесконечного цикла, если сериализатор снова подберет мой CustomListConverter для десериализации определенного элемента списка).
Но, может быть, я ошибаюсь, и есть более понятный подход?
Подробнее здесь: https://stackoverflow.com/questions/798 ... newtonsoft
Мобильная версия