當json數據為 "{\"Data\":[{\"abc\":50},{\"abc\":50.01}]}"時,轉換成DataTable會導致abc列被認定為Int類型。第二條數據的50.01會被轉換成50,導致數據有問題。
處理方式是重寫轉換器,把INT類型的字段用Double類型來代替。避免數據精度丟失。
public class CustomDataTableConverter : DataTableConverter { private static void CreateRow(JsonReader reader, DataTable dt) { DataRow row = dt.NewRow(); reader.Read(); while(reader.TokenType == JsonToken.PropertyName) { string columnName = (string)reader.Value; reader.Read(); DataColumn column = dt.Columns[columnName]; if(column == null) { Type columnDataType = GetColumnDataType(reader); column = new DataColumn(columnName, columnDataType); dt.Columns.Add(column); } if(column.DataType == typeof(DataTable)) { if(reader.TokenType == JsonToken.StartArray) { reader.Read(); } DataTable table = new DataTable(); while(reader.TokenType != JsonToken.EndArray) { CreateRow(reader, table); reader.Read(); } row[columnName] = table; } else if(column.DataType.IsArray && (column.DataType != typeof(byte[]))) { if(reader.TokenType == JsonToken.StartArray) { reader.Read(); } List<object> list = new List<object>(); while(reader.TokenType != JsonToken.EndArray) { list.Add(reader.Value); reader.Read(); } Array destinationArray = Array.CreateInstance(column.DataType.GetElementType(), list.Count); Array.Copy(list.ToArray(), destinationArray, list.Count); row[columnName] = destinationArray; } else { row[columnName] = reader.Value ?? DBNull.Value; } reader.Read(); } row.EndEdit(); dt.Rows.Add(row); } private static Type GetColumnDataType(JsonReader reader) { JsonToken tokenType = reader.TokenType; switch(tokenType) { case JsonToken.StartArray: reader.Read(); if(reader.TokenType != JsonToken.StartObject) { return GetColumnDataType(reader).MakeArrayType(); } return typeof(DataTable); case JsonToken.Integer: return typeof(double); //在此特殊處理int類型 case JsonToken.Float: case JsonToken.String: case JsonToken.Boolean: case JsonToken.Date: case JsonToken.Bytes: return reader.ValueType; case JsonToken.Null: case JsonToken.Undefined: return typeof(string); } throw new JsonException(string.Format("Unexpected Json token while reading DataTable: {0}", tokenType)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { DataTable dt = existingValue as DataTable; if(dt == null) { dt = (objectType == typeof(DataTable)) ? new DataTable() : ((DataTable)Activator.CreateInstance(objectType)); } if(reader.TokenType == JsonToken.PropertyName) { dt.TableName = (string)reader.Value; reader.Read(); } if(reader.TokenType == JsonToken.StartArray) { reader.Read(); } while(reader.TokenType != JsonToken.EndArray) { CreateRow(reader, dt); reader.Read(); } return dt; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { DataTable table = (DataTable)value; DefaultContractResolver contractResolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartArray(); foreach(DataRow row in table.Rows) { writer.WriteStartObject(); foreach(DataColumn column in row.Table.Columns) { if((serializer.NullValueHandling != NullValueHandling.Ignore) || ((row[column] != null) && (row[column] != DBNull.Value))) { writer.WritePropertyName((contractResolver != null) ? contractResolver.GetResolvedPropertyName(column.ColumnName) : column.ColumnName); serializer.Serialize(writer, row[column]); } } writer.WriteEndObject(); } writer.WriteEndArray(); } }
調用方式:
//JObject jo JsonSerializer serializer = new JsonSerializer(); serializer.Converts.Add(new CustomDataTableConverter()); DataTable dt = jo.GetValue("Data").ToObject<DataTable>(serializer);