一尘不染

在自定义类上反序列化DataTable属性后,DateTime列类型变为String类型

json

我的问题与这一问题非常相似,但是我没有足够的声誉对原始答案发表评论。

我有一个名为FillPDF的自定义类,该类在服务器上进行序列化并在客户端上反序列化。

FillPDF dsPDF = JsonConvert.DeserializeObject<FillPDF>(json);

FillPDF班由一个中DataSet包含的一个集合属性DataTables

通过阅读原始问题的解决方案,我知道了为什么将DateTime类型错误地设置为String。我了解Json.Net
仅通过查看第一行来DataTableConverter推断每个推断DataColumn.DataType(我的第一行具有NULL值)。

我试图从原始问题开始实施解决方案。dbc建议覆盖DataTableConverter。我已经做到了,并且settings在序列化和反序列化期间正在使用该对象,如下所示:

// Server
FillPDF pdfData = new FillPDF(strUniqueColID);                    
var settings = new JsonSerializerSettings { Converters = new[] { new TypeInferringDataTableConverter() } };
string json = JsonConvert.SerializeObject(pdfData, Formatting.Indented,settings);


// Client
var settings = new JsonSerializerSettings { Converters = new[] { new TypeInferringDataTableConverter() } };
FillPDF dsPDF = JsonConvert.DeserializeObject<FillPDF>(json,settings);

但是,我没有收到任何错误,并且我的基础DataTable仍未正确反序列化。我认为这是因为我要序列化/反序列化自定义对象,而不是DataTable原始问题中的简单对象。

我想做的是:

if(c.ColumnName.toLower().Contains("date"))
{
   // Set Column's Type to DateTime because I know all Column Names containing "date" should be of type DateTime
}

大概必须将其添加到重写中TypeInferringDataTableConverter

我不太确定从这里要去哪里,所以我急切需要一些帮助!

谢谢,

贾斯汀。


阅读 500

收藏
2020-07-27

共1个答案

一尘不染

这个问题
似乎是,Newtonsoft的DataSetConverter使用会有限制Newtonsoft的DataTableConverterDataTableConverter converter = new DataTableConverter();,然后调用它的ReadJson()直接方法。因此,永远不会使用您的转换器。

一种解决方案DataSetConverter通过改编James Newton-
King的原始代码来创建自己的版本:

public class DataSetConverter<TDataTableConverter> : DataSetConverter where TDataTableConverter : JsonConverter, new()
{
    // This code adapted from 
    // https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataSetConverter.cs
    // Copyright (c) 2007 James Newton-King
    // Licensed under The MIT License (MIT):
    // https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md

    readonly TDataTableConverter converter = new TDataTableConverter();

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }

        // handle typed datasets
        DataSet ds = (objectType == typeof(DataSet))
            ? new DataSet()
            : (DataSet)Activator.CreateInstance(objectType);

        reader.ReadAndAssert();

        while (reader.TokenType == JsonToken.PropertyName)
        {
            DataTable dt = ds.Tables[(string)reader.Value];
            bool exists = (dt != null);

            dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer);

            if (!exists)
            {
                ds.Tables.Add(dt);
            }

            reader.ReadAndAssert();
        }

        return ds;
    }
}

public static class JsonReaderExtensions
{
    public static void ReadAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (!reader.Read())
        {
            new JsonReaderException(string.Format("Unexpected end at path {0}", reader.Path));
        }
    }
}

然后添加DataSetConverter<TypeInferringDataTableConverter>到您的转换器列表。

顺便说一句,如果您需要做的就是将列类型设置为,DateTime当列名包含字符串时"date",您可以考虑创建一个比转换过程更简单的转换TypeInferringDataTableConverter器,以反序列化缺少第一列的数据表

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// ...
  • 让您的分叉转换器子类为Newtonsoft的子类DataTableConverter;删除的所有代码WriteJson()

  • 修改GetColumnDataType()以传递列名并添加必要的逻辑:

    private static Type GetColumnDataType(JsonReader reader, string columnName)
    

    {
    JsonToken tokenType = reader.TokenType;

    switch (tokenType)
    {
        case JsonToken.String:
            if (columnName.IndexOf("date", StringComparison.OrdinalIgnoreCase) >= 0)
                return typeof(DateTime);
            return reader.ValueType;
    
        case JsonToken.Integer:
        case JsonToken.Boolean:
        case JsonToken.Float:
        case JsonToken.Date:
        case JsonToken.Bytes:
            return reader.ValueType;
    
        case JsonToken.Null:
        case JsonToken.Undefined:
            if (columnName.IndexOf("date", StringComparison.OrdinalIgnoreCase) >= 0)
                return typeof(DateTime);
            return typeof(string);
    
        case JsonToken.StartArray:
            reader.ReadAndAssert();
            if (reader.TokenType == JsonToken.StartObject)
            {
                return typeof(DataTable); // nested datatable
            }
    
            Type arrayType = GetColumnDataType(reader, columnName);
            return arrayType.MakeArrayType();
        default:
            throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable: {0}".FormatWith(CultureInfo.InvariantCulture, tokenType));
    }
    

    }

  • 然后将调用固定为GetColumnDataType()在第152行附近传递列名称:

    Type columnType = GetColumnDataType(reader, columnName);
    
  • 存根在任何丢失内部的方法,如ReadAndAssert()与如图静态扩展方法在这里

*创建您自己的Newtonsoft转换器版本 *的替代解决方案
是,在[OnDeserialized]容器类的事件中,使用的其中一个,循环遍历的所有表中的所有DataSet列,并将名称包含为string(或object)类型的列转换为列。如何更改数据表中数据列的数据类型的答案?。"date"``DateTime

2020-07-27