Почему System.Version в строке JSON неправильно десериализуется?

Контекст: мне нужно передать объект, содержащий большое количество свойств / полей (в UI Layer из Middle Tier Layer). Среди этого списка свойств одно имеет тип Version, который неправильно десериализовывается из строкового формата JSON. Я выбрал формат JSON поверх XML, поскольку сериализация JSON в строку вернет короткий результат строки.

Проблема: System.Version не десериализован правильно. Я пробовал две разные библиотеки.NET. Ниже приведены фрагменты кода для каждого:

Фрагмент кода 1 с использованием библиотеки ServiceStack .NET:

        var version = new Version(1, 2, 3, 0);
        string reportJSON = JsonSerializer.SerializeToString<Version>(version);
        //{"Major":1,"Minor":2,"Build":3,"Revision":0,"MajorRevision":0,"MinorRevision":0}


        Version report2 = JsonSerializer.DeserializeFromString<Version>(reportJSON);
        string reportJSON2 = JsonSerializer.SerializeToString<Version>(report2);
        //{"Major":0,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}

Код фрагмента 2 с использованием библиотеки Newtonsoft .NET, но с тем же результатом:

        var version = new Version(1, 2, 3, 0);
        string reportJSON = JsonConvert.SerializeObject(version);
        //{"Major":1,"Minor":2,"Build":3,"Revision":0,"MajorRevision":0,"MinorRevision":0}


        Version report2 = JsonConvert.DeserializeObject<Version>(reportJSON);
        string reportJSON2 = JsonConvert.SerializeObject(report2);
        //{"Major":0,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}

Как это исправить? Или какая другая библиотека JSON.NET может работать правильно?

2 ответа

Newtonsoft.Json Библиотека предоставляет набор общих преобразователей в Newtonsoft.Json.Convertersпространство имен, включая VersionConverterВы можете использовать для сериализации и десериализацииSystem.Version,

Обратите внимание, что вы должны использоватьVersionConverterкак для сериализации, так и для десериализации.
Это потому, что стандартная сериализация будет генерировать, например:{"Major":1,"Minor":2,"Build":3,"Revision":0,"MajorRevision":0,"MinorRevision":0} в то время как VersionConverterдесериализация ожидает простую строку, как в "1.2.3",

Таким образом, использование будет:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;  

string s = JsonConvert.SerializeObject(version, new VersionConverter());
Version v = JsonConvert.DeserializeObject<Version>(s, new VersionConverter());

Я не уверен, что это первая версия Newtonsoft.Jsonэто включает в себя этот конвертер. У меня есть, и это 5.0.6.

Свойства Version У класса нет сеттера. Они просто возвращают значение своих соответствующих приватных полей. Следовательно, десериализатор не может изменять свои значения.

Но с Json.NET вы можете написать собственный класс конвертера, который обрабатывает десериализацию Version учебный класс.

Осторожно: этот код не был проверен очень хорошо...

public class VersionConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // default serialization
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // create a new Version instance and pass the properties to the constructor
        // (you may also use dynamics if you like)
        var dict = serializer.Deserialize<Dictionary<string, int>>(reader);
        return new Version(dict["Major"], dict["Minor"], dict["Build"], dict["Revision"]);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Version);
    }
}

Затем вы должны указать, что вы хотите использовать конвертер:

var v = new Version(1, 2, 3, 4);
string json = JsonConvert.SerializeObject(v);

var v2 = JsonConvert.DeserializeObject<Version>(json, new VersionConverter());

Json.NET решает, использовать ли один из указанных вами преобразователей. Таким образом, вы всегда можете указать конвертер, как показано ниже. Json.NET будет использовать один из ваших конвертеров, если они соответствуют типу в SomeClass,

var result = JsonConvert.DeserializeObject<SomeClass>(json, new VersionConverter());
Другие вопросы по тегам