反序列化缺少第一列的数据表

时间:2015-09-22 20:53:43

标签: json datatable null json.net

我尝试将.NET DataTable序列化为JSON文件,然后将JSON文件反序列化为DataTable。我觉得相当直白。

但是,我有一个表,3行乘3列,每个元素都是double类型。如果第一行中的任何值为null,则当JSON.Net将json文件反序列化为DataTable对象时,第一行中为null的列的所有值都将成为字符串。

要清楚,只有当第一行中的值为空时才会发生这种情况。如果在除第一行之外的任何其他行中任何值为null,则该列中的其余值将保持双精度。

  1. 如果我用double替换null,一切都按预期工作(但是我不能这样做)。

  2. 如果我设置NullValueHandling = NullValueHandling.Ignore,则所有值都保持为双精度,除了第一行现在被列为最后一行:

  3. 示例:

    "Column2": 1.0,
    "Column3": 1.1
    },
    {
       "Column1": 0.0,
       "Column2": 0.5,
       "Column3": 2.0
    },
    

    变为:

      "Column2": 1.0,
      "Column3": 1.1
    },
    {
      "Column2": 0.5,
      "Column3": 2.0,
      "Column1": 0.0
    },
    

    我需要能够反序列化JSON,保持列的顺序,并且第一行中没有空值会导致该行中的所有值成为字符串。我还需要保留第一行的Column1(在上面的例子中)为null - 如果它是空字符串或DBNull,请不要关心。

    有什么想法? (我的测试代码如下......注释/取消注释NullValueHandling以查看问题)

            DataTable table = new DataTable("MyTable");
            table.Columns.Add("Column1", typeof(double));
            table.Columns.Add("Column2", typeof(double));
            table.Columns.Add("Column3", typeof(double));
    
            for (int i = 0; i < 10; i++) {
                if (i == 0)
                    table.Rows.Add(null, 1.0, 1.1);
                else
                   table.Rows.Add(0.0, 0.5, 2.0);
            }
    
            JsonSerializer serializer = new JsonSerializer();
            //serializer.TypeNameHandling = TypeNameHandling.All;
            serializer.NullValueHandling = NullValueHandling.Ignore;
            using (StreamWriter sw1 = new StreamWriter("1st.json"))
            using (JsonWriter writer1 = new JsonTextWriter(sw1))
            {
                writer1.Formatting = Formatting.Indented;
                serializer.Serialize(writer1, table);
            }
    
            DataTable newtable;
            using (StreamReader sr = new StreamReader("1st.json"))
            using (JsonReader reader = new JsonTextReader(sr))
            {
                newtable = (DataTable)serializer.Deserialize(reader, typeof(DataTable));
            }
    
            using (StreamWriter sw = new StreamWriter("3rd.json"))
            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Formatting.Indented;
                serializer.Serialize(writer, newtable);
            }
    

1 个答案:

答案 0 :(得分:1)

Json.NET是MIT License下的开源软件,因此有一种可能性是创建其DataTableConverter的修改版本以满足您的需求。其源代码可用here

首先,创建自己的这个类的分叉版本,称为JsonDefaultTypeDataTableConverter<T>。修改方法GetColumnDataType以返回typeof(T)以获取空列值:

/// <summary>
/// Converts a <see cref="DataTable"/> to and from JSON.
/// Adapted from https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataTableConverter.cs
/// </summary>
public class JsonDefaultTypeDataTableConverter<T>  : JsonConverter
{
    private static Type GetColumnDataType(JsonReader reader)
    {
        JsonToken tokenType = reader.TokenType;

        switch (tokenType)
        {
            case JsonToken.Integer:
            case JsonToken.Boolean:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return reader.ValueType;
            case JsonToken.Null:
            case JsonToken.Undefined:
                return typeof(T); // WAS typeof(string).
            case JsonToken.StartArray:
                CheckedRead(reader);
                if (reader.TokenType == JsonToken.StartObject)
                {
                    return typeof (DataTable); // nested datatable
                }

                Type arrayType = GetColumnDataType(reader);
                return arrayType.MakeArrayType();
            default:
                throw new JsonSerializationException(string.Format("Unexpected JSON token when reading DataTable: {0}", tokenType));
        }
    }
}

您还需要修复调用以在232附近投掷JsonSerializationException,例如:

    private static void CheckedRead(JsonReader reader)
    {
        if (!reader.Read())
        {
            throw new JsonSerializationException(string.Format("Unexpected end when reading DataTable."));
        }
    }

围绕114行:

        if (reader.TokenType != JsonToken.StartArray)
        {
            throw new JsonSerializationException(string.Format("Unexpected JSON token when reading DataTable. Expected StartArray, got {0}.", reader.TokenType));
        }

现在,鉴于您知道您的表中包含double个值的列,您可以像这样使用它:

        JsonSerializer serializer = new JsonSerializer();
        //serializer.TypeNameHandling = TypeNameHandling.All;
        //serializer.NullValueHandling = NullValueHandling.Ignore; -- DO NOT USE THIS OPTION.
        serializer.Converters.Add(new JsonDefaultTypeDataTableConverter<double>());

请注意,在执行此操作时,您不会修改Json.NET本身的内部,而是复制和修改常用的.Net类型的一组标准converters

更新:完整版here