2016-09-20 11 views
3

Newtonsoft.Jsonのバージョンを「8.0.3」から「9.0.1」に更新しました。 変更後、私はダブルスと文字列。 Newtonsoft.JsonバージョンでNewtonsoft.Json.netのdoubleとstringの間の変換に関する問題

public class KeyValue 
    { 
     public string Key { get; set; } 
     public string Value { get; set; }  
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     var json = "{\"Key\": 'test', \"Value\": 210001.0}"; 
     var kv = JsonConvert.DeserializeObject<KeyValue>(json); 
    } 

"8.0.3" - クラスの出力は次のようになります:

はここにいくつかのコードだ キー - "テスト" 値 - "210001" //ません。 Newtonsoft.Jsonバージョン「9.0.1」では0

クラスの出力は キーだろう - 「テスト」 値 - 値が210001.0である場合にのみ、「210001.0」

これが起こる - 210001.1それのためにwオウルは起こらない。 新しいバージョンでこの問題が改善されていることが分かりましたが、旧バージョンのソリューションに依存する外部コードがたくさんあります。 旧バージョンのソリューションはどのように実現できますか?

答えて

2

解決策は間違いなく機能します。カスタムはJsonConverterというプロパティに適用されます。これにより、値がシリアル化/逆シリアル化される方法を制御できます。

最初の手順では、新しいJsonConverterを作成していますが、これは実装が非常に簡単です。私はちょうどdecimalまたはdoubleのどちらかの値にToString()を呼び出します。

public sealed class FloatStringConverter : JsonConverter 
{ 
    public override bool CanWrite { get { return false; } } 

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return reader.Value.ToString(); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(double) || objectType == typeof(decimal); 
    } 
} 

それはFloatParseHandlingの両方の値で動作することができますし、私は私の前の、不正解に提示され、それが値をフォーマットしますので、私はそれを作りました。 FloatParseHandlingを無視したい場合は、好みに合わせて調整することもできますが、タイプチェックが必要です。

FloatParseHandlingのデフォルト値はFloatParseHandling.Doubleなので、シリアライザの設定を変更しなくても正しく動作することを覚えておいてください。

次に行う必要があるのは、プロパティを適切な属性でマークして、シリアライザがそれを使用することを知るようにすることです。

[JsonConverter(typeof(FloatStringConverter))] 
public string Value { get; set; } 

この後、Valueには、JSONからの正しい数値表現が含まれます。

+0

私はこれをコンバーター経​​由で実装したくなかったが、今まで提案された最高のソリューションだと思う。どうもありがとうございました!!! –

+0

@olegchernyakov、予防策として、コンバータの実装を少し変更し、 'CanConvert'の本体を' throw new NotSupportedException(); 'に置き換えることを提案します。 'CanConvert'はプロパティが属性でマークされているときに呼び出されないので、コンバーターが' JsonSerializerSettings.Converters'コレクションに追加されたときにのみ、 'CanConvert'がプロパティの型を受け取るので、いくつかの問題が発生する可能性があります。数値型ではなく「文字列」になります。ボディを削除すると、このコンバータは 'JsonConverterAttribute'でのみ使用されます。 – kiziu

3

これは、明らかにNewtonsoft.Jsonの作成者がJsonSerializerSettings.FloatParseHandlingのデフォルト値を変更したためです。これにより、文字列変換で使用される中間形式が数値から変更されました。デシリアライザは、数タイプとしてDecimalを使用し、あなたが

210001.0M.ToString() 

を実行しようとすると、あなたは

210001.0 

は、番号のDoubleある古い取り扱いに戻すに取得するため0は、文字列の最後に存在し、デシリアライズ時に明示的に指定する必要があります。

JsonConvert.DeserializeObject<KeyValue>(json, new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Double }); 

これは参照demo at dotnetfiddle.net

210001 

を返し

210001D.ToString() 

としてそれを実行するためのデシリアライザを引き起こします。

DecimalからDoubleに変更すると精度が低下する可能性があることに注意してください。

編集: JsonTextReader.ReadStringValueの実装を少し変更してこの問題を追跡しました。バージョン8.0.3では、番号タイプを中間のものとして使用しました。したがって、floatからstringへの逆シリアル化ではFloatParseHandlingが使用されました。バージョン9.0.1では、number型を使用しなくなりました。JSONの部分文字列を取り出し、値として設定しました。

要約すると、私は他の答えからJsonConverter以外のオプションを示唆するのにJSON.netにはあまりよく慣れていません。多分それに精通している人が何かを提供するかもしれない。

+0

数字に依存するコードが違う形式であるが、それでも正しくあるということは、少し匂いがあるという事実を飛ばした。それがもっと深い意味を持っていない限り。 – kiziu

+0

答えをありがとう。このコードはdotnetfiddle上で正常に動作しますが、winformにコピーすると、両方とも(double \ decimal)結果が '.0'になります。私はJson.net 9.0.1パッケージを使用しています。私のプロジェクトは4.5フレームワークを使用しています。 PC上でwinformを開いて結果を確認してください。 –

+1

あなたは正しいですが、ローカルで実行されたときには機能しません。また、全体の非直列化は思ったよりもかなり異なって実行されているようで、私の答えは間違っています。それは残念です。 destinationプロパティが 'string'の場合、変換は行われず、値としてJSONに渡されたものは文字列として扱われ、値として使用されます。私は解決策を投稿しますが、発生した変更の原因を突き止めるために、より多くの調査とデバッグが必要になります。 – kiziu

関連する問題