Десериализация массива объектов в конкретные типы .NET с помощью NewtonsoftC#

Место общения программистов C#
Ответить
Anonymous
 Десериализация массива объектов в конкретные типы .NET с помощью Newtonsoft

Сообщение Anonymous »

У меня есть пара классов (упрощенно):

Код: Выделить всё

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());
Второе утверждение не выполнено (фактический тип — JArray). Я реализовал собственный JsonConverter следующим образом:

Код: Выделить всё

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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»