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

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

问题描述

我正在尝试将.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行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. 如果我更换一个双重的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:

示例: p>

Example:

"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。

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.

任何想法? (我的测试代码下面..评论/取消注释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是开源在麻省理工学院许可证下,所以有一种可能是创建一个修改版本的 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< T> 。修改方法 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));
        }
    }
}

您还需要修复调用在 JsonSerializationException 。 Json / Converters / DataTableConverter.cs#L232rel =nofollow> 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 values,可以这样使用:

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天全站免登陆