反序列化缺少第一列的数据表
deserialize a datatable with a missing first column
我正在尝试将 .NET DataTable 序列化为 JSON 文件,然后将 JSON 文件反序列化回 DataTable。我认为相当简单。
但是,我有一个table,3行3列,每个元素都是double类型。如果第一行中的任何值为空,当 JSON.Net 将 json 文件反序列化为 DataTable 对象时,第一行中为空的列的所有值都将变为字符串。
明确地说,只有当第一行中的值为空时才会发生这种情况。如果除第一行之外的任何其他行中的任何值为空,则该列中的其余值保持双倍。
如果我将 null 替换为双精度值,一切都会按预期工作(但是,我不能这样做)。
如果我设置 NullValueHandling = NullValueHandling.Ignore,所有值都保持为双精度值,除了第一行现在列为最后一行:
示例:
"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。
有什么想法吗? (下面我测试代码..comment/uncomment 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);
}
Json.NET是在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下开源的。
首先,创建你自己的这个 class 的分支版本,比如说,JsonDefaultTypeDataTableConverter<T>
。将方法 GetColumnDataType
修改为 return 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));
}
现在,鉴于您 知道 您的 table 包含 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 本身的内部结构,而是在复制和修改其一组标准 converters 用于常用的 .Net 类型.
更新:完整版here。
我正在尝试将 .NET DataTable 序列化为 JSON 文件,然后将 JSON 文件反序列化回 DataTable。我认为相当简单。
但是,我有一个table,3行3列,每个元素都是double类型。如果第一行中的任何值为空,当 JSON.Net 将 json 文件反序列化为 DataTable 对象时,第一行中为空的列的所有值都将变为字符串。
明确地说,只有当第一行中的值为空时才会发生这种情况。如果除第一行之外的任何其他行中的任何值为空,则该列中的其余值保持双倍。
如果我将 null 替换为双精度值,一切都会按预期工作(但是,我不能这样做)。
如果我设置 NullValueHandling = NullValueHandling.Ignore,所有值都保持为双精度值,除了第一行现在列为最后一行:
示例:
"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。
有什么想法吗? (下面我测试代码..comment/uncomment 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);
}
Json.NET是在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下开源的。
首先,创建你自己的这个 class 的分支版本,比如说,JsonDefaultTypeDataTableConverter<T>
。将方法 GetColumnDataType
修改为 return 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));
}
现在,鉴于您 知道 您的 table 包含 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 本身的内部结构,而是在复制和修改其一组标准 converters 用于常用的 .Net 类型.
更新:完整版here。