You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JsonConvert序列化DataTable正常但反序列化报错的解决方法

问题描述

我有一个DataTable,用JsonConvert.SerializeObject序列化JSON正常,结果如下:

[
  {
    "String": null,
    "Int": 1,
    "Double": 1.0,
    "Boolean": false,
    "Date": "2022-09-30T00:00:00",
    "DateTime": "2022-09-30T00:00:00",
    "List of strings": [
      "A",
      "C"
    ],
    "List of floats": [
      1.0,
      2.0
    ],
    "List of dates": "[datetime.date(2022, 9, 30)]",
    "Dictionary String - Flaot": {
      "A": 1.0
    },
    "Dictionary String - List of floats": {
      "A": [
        1.0
      ]
    }
  },
  {
    "String": null,
    "Int": 2,
    "Double": 2.0,
    "Boolean": true,
    "Date": "2021-01-01T00:00:00",
    "DateTime": "2021-01-01T00:00:00",
    "List of strings": [
      "B",
      "D"
    ],
    "List of floats": [
      3.0,
      4.0
    ],
    "List of dates": "[datetime.date(2022, 1, 1), datetime.date(2022, 2, 2)]",
    "Dictionary String - Flaot": {
      "B": 2.0,
      "C": 3.0
    },
    "Dictionary String - List of floats": {
      "B": [
        2.0,
        3.0
      ],
      "C": [
        12.0
      ]
    }
  }
]

但调用JsonConvert.DeserializeObject<DataTable>(上述JSON字符串)时抛出错误:

JsonSerializationException: Unexpected JSON token when reading DataTable: StartObject. Path '[0]['Dictionary String - Flaot']', line 18, position 34.
   at Newtonsoft.Json.Converters.DataTableConverter.GetColumnDataType(JsonReader reader)
   at Newtonsoft.Json.Converters.DataTableConverter.CreateRow(JsonReader reader, DataTable dt, JsonSerializer serializer)
   at Newtonsoft.Json.Converters.DataTableConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
原因分析

Newtonsoft.Json的默认DataTableConverter仅支持简单值类型和一维数组,无法处理嵌套对象(比如Dictionary<string, T>)或复杂嵌套数组结构。反序列化时,转换器遇到{(StartObject)标记时,无法识别该类型作为DataTable的列值,直接抛出异常。

解决办法

方案1:改用强类型实体类(推荐)

放弃DataTable,定义匹配JSON结构的强类型类,完美支持嵌套结构的序列化与反序列化:

public class DataItem
{
    public string String { get; set; }
    public int Int { get; set; }
    public double Double { get; set; }
    public bool Boolean { get; set; }
    public DateTime Date { get; set; }
    public DateTime DateTime { get; set; }
    public List<string> ListOfStrings { get; set; }
    public List<double> ListOfFloats { get; set; }
    public string ListOfDates { get; set; } // 原JSON中为字符串格式的日期列表,直接用string接收
    public Dictionary<string, double> DictionaryStringFloat { get; set; }
    public Dictionary<string, List<double>> DictionaryStringListOfFloats { get; set; }
}

// 反序列化调用
var dataList = JsonConvert.DeserializeObject<List<DataItem>>(jsonString);

方案2:自定义JsonConverter处理DataTable的复杂字段

如果必须使用DataTable,可自定义转换器,将字典等复杂类型序列化为JSON字符串,反序列化时再解析回对象:

public class ComplexDataTableConverter : DataTableConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var dt = base.ReadJson(reader, objectType, existingValue, serializer) as DataTable;
        if (dt == null) return null;

        // 处理字典类型列,将JSON字符串反序列化为Dictionary
        foreach (DataRow row in dt.Rows)
        {
            foreach (DataColumn col in dt.Columns)
            {
                if (col.ColumnName.Contains("Dictionary") && row[col] is string jsonStr && !string.IsNullOrEmpty(jsonStr))
                {
                    // 根据实际字段类型调整反序列化目标
                    if (col.ColumnName == "Dictionary String - Flaot")
                    {
                        row[col] = JsonConvert.DeserializeObject<Dictionary<string, double>>(jsonStr);
                    }
                    else if (col.ColumnName == "Dictionary String - List of floats")
                    {
                        row[col] = JsonConvert.DeserializeObject<Dictionary<string, List<double>>>(jsonStr);
                    }
                }
            }
        }
        return dt;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dt = value as DataTable;
        if (dt == null) return;

        // 序列化前将字典转为JSON字符串
        foreach (DataRow row in dt.Rows)
        {
            foreach (DataColumn col in dt.Columns)
            {
                if (row[col] is IDictionary dict)
                {
                    row[col] = JsonConvert.SerializeObject(dict);
                }
            }
        }

        base.WriteJson(writer, dt, serializer);
    }
}

// 使用方式
var settings = new JsonSerializerSettings();
settings.Converters.Add(new ComplexDataTableConverter());

// 序列化
var json = JsonConvert.SerializeObject(dataTable, settings);

// 反序列化
var dt = JsonConvert.DeserializeObject<DataTable>(json, settings);

方案3:手动预处理JSON字符串(临时方案)

若不想修改代码结构,可手动将JSON中的字典对象转为字符串后再反序列化:

// 预处理:将字典对象转为JSON字符串(需根据实际字段调整替换规则)
var processedJson = jsonString
    .Replace("\"Dictionary String - Flaot\": {", "\"Dictionary String - Flaot\": \"{")
    .Replace("},", "}\",")
    .Replace("\"Dictionary String - List of floats\": {", "\"Dictionary String - List of floats\": \"{")
    .Replace("}]", "}\"]");

// 反序列化
var dt = JsonConvert.DeserializeObject<DataTable>(processedJson);

// 反序列化后手动解析字典字段
foreach (DataRow row in dt.Rows)
{
    var floatDictJson = row["Dictionary String - Flaot"].ToString();
    row["Dictionary String - Flaot"] = JsonConvert.DeserializeObject<Dictionary<string, double>>(floatDictJson);

    var listDictJson = row["Dictionary String - List of floats"].ToString();
    row["Dictionary String - List of floats"] = JsonConvert.DeserializeObject<Dictionary<string, List<double>>>(listDictJson);
}

注意:该方案仅适合临时场景,JSON结构变化时需同步修改替换规则,维护成本较高。

内容的提问来源于stack exchange,提问作者Math122

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:36:06