2011-11-28 8 views
16

私はいくつかのプロパティをDictionary<string, object>にデシリアライズしています。数値の逆シリアル化のデフォルトのタイプを変更するにはどうすればよいですか?

私はいくつかのJSONを逆シリアル化すると、Int32ではなくInt64オブジェクトでDictionaryを設定します。 Int32をデフォルトの井戸として選択して、変換時にオーバーフローするJavaScript数値を持つことができることを知りたいと思います。その場合の例外の投棄は完全に容認されるだろう。

これを達成する方法はありますか?私はいくつかの素敵な属性や、JsonSerializerに実装して追加できる便利なインターフェースを期待しています。そして、私はJson.NETの深みまで深く掘り下げなければならないことを恐れている。

基本的に私は私が代わりにStringsの代わりにInt64DateTimesInt32年代を得ることができるように、オブジェクトのための既知の型を制御するいくつかの方法を持っていると思います。

+0

コメント:OPはPOCOオプションを認識しているが、 –

答えて

18

私が知る限り、これを行うための組み込みの方法はありません。

この件にはissueがありましたが、終了しました。 問題について著者からのいくつかのコメント:値はのInt32やInt64型であるべきかどうかを知る方法がないため

Json.NETデフォルトでは、Int64型として整数値を読み込み、Int64のは、オーバーフローになりにくいです。型指定されたプロパティの場合、デシリアライザはInt64をInt32に変換することを認識していますが、プロパティが型指定されていないためInt64が取得されています。 [...]これは、Json.NETが動作する方法です。

最も簡単な解決策はcoureのDictionary<string, int>に種類を変更することですが、私はあなたが数値を読んでいるだけではなく、したがって、objectで立ち往生していると仮定します。

別のオプションはSerialization Callbacksを使用して、手動Int32にそれらのInt64 Sを変換したり、独自のContract ResolverJsonConverterを作成し、直接(縮小)直列化を制御のいずれかになります。


編集:私はより具体的には少し例を作成しました。

public class Int32Converter : JsonConverter { 
    public override bool CanConvert(Type objectType) { 
     // may want to be less concrete here 
     return objectType == typeof(Dictionary<string, object>); 
    } 

    public override bool CanWrite { 
     // we only want to read (de-serialize) 
     get { return false; } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { 
     // again, very concrete 
     Dictionary<string, object> result = new Dictionary<string, object>(); 
     reader.Read(); 

     while (reader.TokenType == JsonToken.PropertyName) { 
      string propertyName = reader.Value as string; 
      reader.Read(); 

      object value; 
      if (reader.TokenType == JsonToken.Integer) 
       value = Convert.ToInt32(reader.Value);  // convert to Int32 instead of Int64 
      else 
       value = serializer.Deserialize(reader);  // let the serializer handle all other cases 
      result.Add(propertyName, value); 
      reader.Read(); 
     } 

     return result; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { 
     // since CanWrite returns false, we don't need to implement this 
     throw new NotImplementedException(); 
    } 
} 

あなたはどちらかの使用があなたのコンバータまたは(縮小)Serializeメソッドへpass it as parameterを持つメンバーを飾るために属性をすることができます

はここだけ、あなたのspecifc辞書で動作する非常に基本的なコンバータです。

[JsonObject] 
public class MyObject { 
    [JsonConverter(typeof(Int32Converter))] 
    public Dictionary<string, object> Properties { get; set; } 
} 

そして、ここで私は実装をテストするために使用されるコードだ:ここで私は属性使用例ですコンバータなしで

class Program { 
    static void Main(string[] args) { 
     MyObject test = new MyObject(); 
     test.Properties = new Dictionary<string, object>() { { "int", 15 }, { "string", "hi" }, { "number", 7 } }; 
     Print("Original:", test); 

     string json = JsonConvert.SerializeObject(test); 
     Console.WriteLine("JSON:\n{0}\n", json); 

     MyObject parsed = JsonConvert.DeserializeObject<MyObject>(json); 
     Print("Deserialized:", parsed); 
    } 

    private static void Print(string heading, MyObject obj) { 
     Console.WriteLine(heading); 
     foreach (var kvp in obj.Properties) 
      Console.WriteLine("{0} = {1} of {2}", kvp.Key, kvp.Value, kvp.Value.GetType().Name); 
     Console.WriteLine(); 
    } 
} 

が、結果は次のようになります。

Deserialized: 
int = 15 of Int64 
string = hi of String 
number = 7 of Int64 

コンバータでは、

Deserialized: 
int = 15 of Int32 
string = hi of String 
number = 7 of Int32 
+0

何全く素晴らしい答えていることをしたくはありません。 Int32Converterクラスはまさに私が探していたものです。私はこれらのことをどうやって変えてから使用するつもりはありませんが、当時は完璧な答えでした。 :) – Mithon

+0

これは、辞書に整数値がある場合に問題なく動作します。しかし、辞書内のオブジェクトに整数値がある場合、それは機能しません。これについての提案はどうですか? Dictionaryに{{"First"、1 "、Second"、2}}がある場合は動作しません。 Dictionaryに{{"First"、{Age: "1"}}、{"Second "、{Age:" 2 "}} –

+0

@HamidShahidは、どのように逆シリアル化を行うかによって異なります。辞書のオブジェクト( 'Age'フィールドを持つオブジェクト)を所有している場合は、辞書ではなくコンバーターを作成できます。しかし、あなたがいろいろなオブジェクトを扱っているなら、私はそれをお勧めしません。 [ここ](http://stackoverflow.com/questions/17745866/how-can-i-restore-the-int-deserialization-behavior-after-upgrading-json-net)のような一般的な数値コンバータを作成することができます。私の答えはかなり古いものであり、今のところ組み込みのソリューションがあるかもしれないことに留意してください。 – enzi

1

私はEnziの答えを受け入れている、それは私が求めていたものなので。

しかし、以来、私は戦略を変えました。

今、私はChangeSet<T>にデシリアライズしています。辞書の代わりに強く型付けされたEntity(T)オブジェクトがあります。また、着信jsonに存在するプロパティのプロパティ名を持つList<string>があります。デシリアライズ時にカスタムMediaFormatterを使用してそのリストを作成します。そうすれば、強く型付けされたオブジェクトが得られ、すべてのプロパティの逆シリアル化が正しく行われます。リストから、バッチ処理を実行するときにTのコレクションに設定するプロパティを知っています。

このように、私は基本的にDTOとしてエンティティを使用していますが、バッチ操作ごとに無数の異なるDTOを持つ必要はありません。もし私がそう言えば、かなり滑らかです。 :)

1

は反復一度Dictionary<string,object>

var variable = Convert.ToInt32(object) 

を試してみて、あなたがobjectを読むたびに、このInt32とのobjectを書き換え、またはInt32変換を行います。

1

これは私のためにうまく機能している:片付け

public class ParseNumbersAsInt32Converter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(long) || objectType == typeof(long?) || objectType == typeof(object); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.Value != null && reader.Value is long) 
     { 
      return Convert.ToInt32(reader.Value); 
     } 
     return reader.Value; 
    } 
} 
+0

この回答は、JsonConvertを無効にしてより多くの機能を追加する方がはるかに簡単でした。ありがとう –

関連する問題