JSON反序列化为DataTable时浮点数被转为整数的问题求解
解决JSON反序列化为DataTable时浮点数被转成整数的问题
我之前也碰到过一模一样的情况!问题出在Json.NET反序列化为DataTable时的自动类型推断逻辑——它会根据JSON数组里第一个元素的字段值来确定整个列的数据类型。你看你的第一条数据里Discount是整数20,所以它直接把Discount列的类型设成了Int32,后面的10.3、15.5就被强制截断成整数了,哪怕你设置了FloatParseHandling.Decimal也没用,因为列类型已经被固定成整数了。
下面给你几个靠谱的解决方案,按推荐程度排序:
方案一:用自定义实体类反序列化(最推荐)
先定义一个和JSON结构匹配的实体类,明确指定所有数值字段为decimal类型,这样反序列化时就不会出现类型推断错误:
public class ImportProduct { public string ProdName { get; set; } public decimal Qty { get; set; } public decimal Rate { get; set; } public decimal Discount { get; set; } }
然后先把JSON反序列化为List<ImportProduct>,再转换成DataTable:
// 反序列化为实体列表 var productList = JsonConvert.DeserializeObject<List<ImportProduct>>( objParam["ImportData"].ToString(), new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Decimal } ); // 转换为DataTable DataTable dt = ToDataTable(productList);
这里需要一个通用的List<T>转DataTable的工具方法:
public static DataTable ToDataTable<T>(List<T> items) { DataTable dataTable = new DataTable(typeof(T).Name); // 获取实体类的所有公共属性 PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); // 添加列到DataTable foreach (PropertyInfo prop in props) { // 处理可空类型 Type columnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; dataTable.Columns.Add(prop.Name, columnType); } // 填充数据行 foreach (T item in items) { object[] values = new object[props.Length]; for (int i = 0; i < props.Length; i++) { values[i] = props[i].GetValue(item, null) ?? DBNull.Value; } dataTable.Rows.Add(values); } return dataTable; }
这种方法类型安全,扩展性也强,后续字段变更只需要修改实体类就行。
方案二:手动创建DataTable并指定列类型
如果你不想定义实体类,可以先手动创建DataTable并明确指定每一列的类型,再逐行解析JSON数据填充:
// 手动创建DataTable,指定所有数值列为decimal DataTable dt = new DataTable(); dt.Columns.Add("ProdName", typeof(string)); dt.Columns.Add("Qty", typeof(decimal)); dt.Columns.Add("Rate", typeof(decimal)); dt.Columns.Add("Discount", typeof(decimal)); // 把JSON字符串解析为JArray JArray importDataArray = JArray.Parse(objParam["ImportData"].ToString()); // 逐行填充数据 foreach (JObject productObj in importDataArray) { DataRow row = dt.NewRow(); row["ProdName"] = productObj["ProdName"].ToString(); row["Qty"] = productObj["Qty"].Value<decimal>(); row["Rate"] = productObj["Rate"].Value<decimal>(); row["Discount"] = productObj["Discount"].Value<decimal>(); dt.Rows.Add(row); }
这种方法直接控制列的类型,完全避免了自动推断的问题,适合临时快速解决问题。
方案三:临时调整JSON数据顺序(不推荐)
如果你只是临时测试,可以把第一条数据的Discount改成带小数的形式(比如20.0),这样Json.NET会推断Discount列为decimal类型。但这种方法依赖数据顺序,一旦后续JSON的第一条数据又变成整数,问题会再次出现,所以不建议在生产环境使用。
内容的提问来源于stack exchange,提问作者mangesh
相关产品推荐
相关产品推荐

