9

実行中の動的言語によって作成されたオブジェクト.NETを逆シリアル化するコードがいくつかあります。ソースは動的であるため、整数値を float 形式でシリアル化することがあります (たとえば、2 は "2.0" にシリアル化されます)。JSONwebservice

ではJson.NET 4.0.4、これはシームレスに機能しました(デシリアライズ時に丸めが適用されたようです)。ただし、へのアップグレードにより、Json.NET 4.52.0 を逆シリアル化するとFormatException. コードは次のとおりです。

// works as expected in both versions
var s = "2";
Console.WriteLine(JsonConvert.DeserializeObject<int>(s));

// throws FormatException in 4.5 only
var s = "2.0";
Console.WriteLine(JsonConvert.DeserializeObject<int>(s));

// throws FormatException in 4.5, rounds to 3 in 4.0.4
var s = "2.6";
Console.WriteLine(JsonConvert.DeserializeObject<int>(s));

元の動作を復元する簡単な方法はありますか? 理想的な動作は、整数値を持つ数値のみを逆シリアル化することですが、任意の形式 (たとえば、2.0、1e10、2.5 ではありません) ですが、私は 4.0.4 の動作に落ち着きます。

4

1 に答える 1

6

JsonConverterこれを行うには、小数値の丸め (または破棄) を処理するカスタムを作成します。次のようになります。

class CustomIntConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(int));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JValue jsonValue = serializer.Deserialize<JValue>(reader);

        if (jsonValue.Type == JTokenType.Float)
        {
            return (int)Math.Round(jsonValue.Value<double>());
        }
        else if (jsonValue.Type == JTokenType.Integer)
        {
            return jsonValue.Value<int>();
        }

        throw new FormatException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

その後、次のようにカスタム コンバーターを使用できます。

JsonSerializerSettings settings = new JsonSerializerSettings 
{
    Converters = new List<JsonConverter> { new CustomIntConverter() } 
};

string json = @"[2.6, 0, 4.1, 5, -3, -2.2]";

List<int> list = JsonConvert.DeserializeObject<List<int>>(json, settings);

foreach (int val in list)
{
    Console.WriteLine(val);
}

上記の出力は次のようになります。

3
0
4
5
-3
-2

コンバーターが小数値を四捨五入するのではなく無視する場合は、次のコード行を置き換えます。

        return (int)Math.Round(jsonValue.Value<double>());

これとともに:

        return (existingValue ?? default(int));

その変更を行った後、上記のテスト コードの出力は次のようになります。

0
0
0
5
-3
0
于 2013-07-19T15:20:51.847 に答える