如何根据自定义Schema反序列化JSON到DataSet并修改列数据类型
解决方案
核心问题说明
你原有实现的错误在于:.NET 中 DataColumn.DataType 属性不支持在 DataTable 已填充数据的场景下直接修改,直接赋值会抛出 ArgumentException 异常。你需要调整实现逻辑,先按照自定义Schema构建符合类型要求的空表结构,再对原始数据做类型转换后填充。
完整实现代码
using Newtonsoft.Json; using System; using System.Data; using System.Collections.Generic; static void JsonToDataSet(ref DataSet pDs, string json, string schema) { // 1. 反序列化原始JSON得到源数据 DataSet originalDs = JsonConvert.DeserializeObject<DataSet>(json); DataTable originalTable = originalDs.Tables[0]; // 2. 解析自定义Schema配置 var schemaObj = JsonConvert.DeserializeObject<SchemaRoot>(schema); // 3. 新建符合Schema类型要求的空表 DataTable targetTable = new DataTable(originalTable.TableName); foreach (var fieldConfig in schemaObj.schema) { Type colType = GetColumnType(fieldConfig.type); targetTable.Columns.Add(fieldConfig.field, colType); } // 4. 遍历原始数据,做类型转换后写入新表 foreach (DataRow originalRow in originalTable.Rows) { DataRow newRow = targetTable.NewRow(); foreach (var fieldConfig in schemaObj.schema) { string fieldName = fieldConfig.field; object originalValue = originalRow[fieldName]; newRow[fieldName] = ConvertValue(originalValue, fieldConfig.type); } targetTable.Rows.Add(newRow); } // 5. 赋值给返回的DataSet pDs = new DataSet(); pDs.Tables.Add(targetTable); } // 类型映射:自定义Schema的类型对应.NET类型 private static Type GetColumnType(string schemaType) { return schemaType switch { "int" => typeof(int), "date" => typeof(DateTime), "bool" => typeof(bool), "string" => typeof(string), _ => typeof(string) // 未知类型默认用string }; } // 数值转换:处理各类原始值到目标类型的转换 private static object ConvertValue(object originalValue, string targetType) { if (originalValue == DBNull.Value || originalValue == null) return DBNull.Value; string valueStr = originalValue.ToString().Trim(); if (string.IsNullOrEmpty(valueStr)) return DBNull.Value; try { return targetType switch { "int" => int.Parse(valueStr), "date" => DateTime.Parse(valueStr), "bool" => ConvertToBool(valueStr), _ => valueStr }; } catch { // 转换失败返回空,可根据业务需求调整为默认值 return DBNull.Value; } } // 处理各类布尔值格式的转换:支持0/1、"0"/"1"、"Sim"/"Não"等场景 private static bool ConvertToBool(string valueStr) { if (bool.TryParse(valueStr, out bool boolVal)) return boolVal; if (int.TryParse(valueStr, out int intVal)) return intVal != 0; // 适配示例中的葡萄牙语是/否值 return valueStr.Equals("Sim", StringComparison.OrdinalIgnoreCase); } // 自定义Schema的序列化辅助类 public class SchemaField { public string field { get; set; } public string type { get; set; } } public class SchemaRoot { public List<SchemaField> schema { get; set; } }
注意事项
- 代码已经适配了你示例中的特殊布尔值场景:数字0/1、字符串"0"/"1"、葡萄牙语的"Sim"/"Não"都可以正确转换为布尔类型
- 如果有其他特殊的格式转换需求,可以直接修改
ConvertValue和ConvertToBool方法的逻辑 - 转换失败时默认返回DBNull,你可以根据自己的业务需求调整为抛出异常或者设置默认值
内容的提问来源于stack exchange,提问作者Giovane Winck
相关产品推荐
相关产品推荐

