2012-11-01 5 views
10

コンテキスト:多数のプロパティ/フィールドを含むオブジェクトを中間層からUIレイヤに渡す必要があります。このプロパティのリストの中には、バージョンがJSON文字列形式から正しく非直列化されないバージョンのものがあります。私はJSONのシリアル化が短い文字列の結果を返すため、XML上で選択されたJSON形式を持っています。System.VersionのJSON文字列が正しくデシリアライズされないのはなぜですか?

問題: System.Versionが正しくデシリアライズされません。私は2つの異なる.NETライブラリを試しました。以下のそれぞれのコードスニペットです:ServiceStack .NET libraryを使用して

コードスニペット1:

 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 libraryを使用しても同じ結果と:この問題を解決する方法

 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ライブラリが正しく動作するのですか?

+0

[JavascriptSerializerを使用して不変オブジェクトに逆シリアル化できますか?](http://stackoverflow.com/questions/4080644/can-i-deserialize-to-an-immutable-object-using-javascriptserializer) – spender

+0

@spender:しかし、それは不変の文字列オブジェクトでうまく動作します。 – Monish

+1

@Monish [Here](http://stackoverflow.com/a/2085890/1180426)は、 'Version'クラスがXMLシリアライザブルではない理由を説明するリンクですが、JSONシリアライザにも同じメカニズムが適用されると確信しています。 –

答えて

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が決定します指定したコンバーターのいずれかを使用するかどうかを指定します。したがって、以下に示すように、常にコンバータを指定することができます。 SomeClass内の型と一致する場合、Json.NETは変換器の1つを使用します。

var result = JsonConvert.DeserializeObject<SomeClass>(json, new VersionConverter()); 
12

Newtonsoft.Jsonライブラリには、シリアライズとSystem.Versionをデシリアライズするために使用することができますVersionConverter含め、Newtonsoft.Json.Converters名前空間に共通する変換のセットを提供します。

でも、シリアル化とデシリアライズの両方で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です。

+0

JsonSerializerSettingsオブジェクトを取得するDeserializeObjectシグネチャを使用しているので、私は少しだけ変更しなければなりませんでした。 settings.Converters.Add(新しいVersionConverter()); (過負荷は設定とコンバータのコレクションの両方を使用しません) – Alonzzo2

関連する問題