反序列化缺少第一列的数据表 [英] deserialize a datatable with a missing first column

查看:22
本文介绍了反序列化缺少第一列的数据表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 .NET DataTable 序列化为 JSON 文件,然后将 JSON 文件反序列化回 DataTable.我认为相当简单.

I'm attempting to serialize a .NET DataTable to a JSON file and then deserialize the JSON file back into a DataTable. Fairly straightforward I thought.

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

However, I have a table, 3 rows by 3 columns, each element is of type double. If any value in the first row is null, when JSON.Net deserializes the json file to a DataTable object, all values of the column that was null in the first row become strings.

明确地说,只有当第一行中的值为空时才会发生这种情况.如果除第一行之外的任何其他行中的任何值为空,则该列中的其余值仍为双倍.

To be clear, it is only if a value in the first row is null that this happens. If any values are null in any other row than the first, the remaining values in that column remain doubles.

  1. 如果我用 double 替换 null,一切都会按预期进行(但是,在我的情况下,我不能这样做).

  1. If I replace the null with a double, everything works as expected (I can't do this in my case, however).

如果我设置 NullValueHandling = NullValueHandling.Ignore,除了第一行现在被列为最后一行:

If I set NullValueHandling = NullValueHandling.Ignore, all values stay as doubles, except the first row now gets listed as the last row:

示例:

"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(在上面的例子中)保持为空——不管它是空字符串还是 DBNull.

I need to be able to deserialize the JSON, keep the Columns in order, and not have null values in the first row cause all values in that row to become strings. I also need to keep the Column1 of the first row (in the case above) null - don't care if it is a null string or a DBNull.

有什么想法吗?(我下面的测试代码..comment/uncomment NullValueHandling 看看问题)

Any thoughts? (My test code below..comment/uncomment NullValueHandling to see the problem)

        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);
        }

推荐答案

Json.NET 在 MIT 许可证,因此一种可能性是创建其 DataTableConverter 以满足您的需求.其源代码可在此处.

Json.NET is open source under the MIT License, so one possibility would be to create a modified version of its DataTableConverter to suit your needs. Its source code is available here.

首先,创建您自己的此类的分支版本,例如,JsonDefaultTypeDataTableConverter.修改方法GetColumnDataType 为空列值返回 typeof(T) :

First, create your own forked version of this class, called, say, JsonDefaultTypeDataTableConverter<T>. Modify the method GetColumnDataType to return typeof(T) for a null column value:

/// <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,例如如下:

You'll also need to fix the calls to throw a JsonSerializationException at around line 232, for instance as follows:

    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值的列,您可以像这样使用它:

Now, given that you know your table contains columns of double values, you can use it like this:

        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 类型.

Note that, in doing this, you're not modifying the internals of Json.NET itself, you're copying and modifying one of its set of standard converters for commonly used .Net types.

更新:完整版这里.

这篇关于反序列化缺少第一列的数据表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆