Newtonsoft JSON- 与 DataSet 的转换导致 Decimal 变为 Double?

Posted

技术标签:

【中文标题】Newtonsoft JSON- 与 DataSet 的转换导致 Decimal 变为 Double?【英文标题】:Newtonsoft JSON- Conversion to/from DataSet causes Decimal to become Double? 【发布时间】:2017-03-08 09:48:14 【问题描述】:

我正在使用 Newtonsoft JSON 使用下面的代码将 DataSet 序列化为二进制 JSON。反序列化回 DataSet 时,字段类型从 Decimal 变为 Double?有人知道怎么回事吗?

示例代码:

static void Main(string[] args)

  var ds = new DataSet();
  var dt = ds.Tables.Add();
  dt.Columns.Add("Test", typeof(Decimal));
  dt.Rows.Add(new object[]  1.23345M );

  var data = DataSetToBinJSON(ds);

  var ds2 = BinJSONToDataSet(data);
  Console.WriteLine((ds2.Tables[0].Columns[0].DataType == typeof(Decimal)) ? "Passed" : string.Format("Failed- 0", ds2.Tables[0].Columns[0].DataType));
  Console.ReadLine();




/// <summary>
/// Utility function to create an optimized Binary JSON version of a DataSet
/// </summary>
public static byte[] DataSetToBinJSON(DataSet dataSet)

  if (dataSet == null || dataSet.Tables == null || dataSet.Tables.Count == 0)
  
    return null;
  

  using (var ms = new MemoryStream())
  
    using (var writer = new BsonWriter(ms))
    
      var serializer = new JsonSerializer();
      serializer.Serialize(writer, dataSet);
      return ms.ToArray();
    
  



/// <summary>
/// Utility function to deserialize an optimized Binary JSON serialized DataSet
/// </summary>   
public static DataSet BinJSONToDataSet(byte[] dataBytes)

  if (dataBytes.Length == 0)
  
    return null;
  

  using (var ms = new MemoryStream(dataBytes))
  
    using (var reader = new BsonReader(ms))
    
      var serializer = new JsonSerializer();
      return serializer.Deserialize<DataSet>(reader);
    
  

【问题讨论】:

这不是错误,这是正常行为。 Json格式不区分float/double/decimal类型,但是可以实现自己的JsonTextReader。解决方案:***.com/a/9916087/835720 @oakio- 非常感谢。通过简单地检查源来弄清楚这一点!期望 Newtonsoft 序列化的行为类似于:chrish.com.au/blog/json-netdeserializing-a-datatable。 【参考方案1】:

修复这个集合的简单方法FloatParseHandling = FloatParseHandling.Decimal

示例

    public class Foo
    
        public object Value  get; set; 
    

    Foo original = new Foo
        
            Value = 1.23m
        ;

    string json = JsonConvert.SerializeObject(original);

    var settings = new JsonSerializerSettings
        
            FloatParseHandling = FloatParseHandling.Decimal //hint
        ;
    Foo actual = JsonConvert.DeserializeObject<Foo>(json, settings);

    // actual.Value.GetType() == 'Decimal'

【讨论】:

奥基奥。你对这个问题的评论就是答案,所以我接受这个回复的答案。这很有趣,但不是我想要的。我一直在寻找 100% 无损的 DataSet Binary Json 序列化,但结果证明我可以使用简单的序列化。【参考方案2】:

我怀疑这与DataSetDataTable 的标准(XML)序列化有关。

如果您将示例中的DataSet 写入文件,您将看到未提供有关DataTable 架构的信息。这可以在将 XML 文件读回表时确定。

您的示例中写入文件的数据给出了以下结果:

<NewDataSet>
  <Table1>
    <Test>1.23345</Test>
  </Table1>
</NewDataSet>

DataSetDataTable 已被读取时,您无法更改列的类型(在我的测试案例中,当往返 XML 时,类型是 string)但您可以 .Clone() DataTable 并移动/转换数据:

var clonedTable = ds.Tables[0].Clone();
clonedTable.Columns[0].DataType = typeof(decimal);
foreach (DataRow row in dt.Tables[0].Rows) 
    clonedTable.ImportRow(row);

【讨论】:

您好,谢谢,但这是二进制 JSON,而不是 XML? Newtonsoft 完成的转换使用其自己的 DataSet JSON 格式,而不是 Microsoft XML 标准。但是,您是对的,生成的 JSON 类似于您提供的 XML(没有类型):"Table1":["Test":1.23345] 请忽略以上评论。我的印象是 Newtonsoft 所做的转换使用自己的 DataSet JSON 格式,而不是标准的序列化。我依赖 100% 无损 DataSet 转换,但我想这是不可能的。 只需查看源代码github.com/JamesNK/Newtonsoft.Json/blob/master/Src/…,即可清楚地发现任何非整数都会转换为双精度数。

以上是关于Newtonsoft JSON- 与 DataSet 的转换导致 Decimal 变为 Double?的主要内容,如果未能解决你的问题,请参考以下文章

Newtonsoft.Json 的使用与高级运用

无法解决“Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed”与“Newtonsoft

HttpClient PostAsJsonAsync 与 Newtonsoft.Json 不兼容

Newtonsoft JSON - 不同的JSON结构,对象与数组[重复]

如何使用与 NewtonSoft (JSON.Net) 组件中的 JSON 匹配的 Swift 类从/向 JSON 读取/写入对象数组?

Newtonsoft.Json.JsonConvert 序列化与反序列化