子类化数据表在序列化/反序列化期间将数据类型信息从双精度更改为字符串

本文关键字:信息 数据类型 双精度 字符串 数据表 序列化 反序列化 子类 | 更新日期: 2023-09-27 18:37:23

作为这个问题的背景,我想将一个"代码制作"DataTable绑定到一个aspx:GridView。为了保留此表,我实现了ISerializable接口。表显示正确,但在对行进行排序的回发中,由于行中的元素,会引发InvalidCastExcpetion。项目数组从类型 double 更改为类型 string

注意:两个构造函数,一个用于构造 DataTable 初始值,另一个用于在反序列化过程中构造表:

   [global::System.Serializable()]
   [global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedTableSchema")]
    public partial class HeatMapVisualisationDataTable : DataTable, System.Runtime.Serialization.ISerializable
    {
        #region members
        public double _valueMin { get; private set; }
        public double _valueMax { get; private set; }
        #endregion membders
        public HeatMapVisualisationDataTable(XemlExperimentHeatMapDataTable data)
            : base("result", "http://gmd.mpimp-golm.mpg.de/HeatMap")
        {
            this.Columns.Add(new DataColumn("metabolite", typeof(Guid)));
            this.Columns.Add(new DataColumn("name", typeof(string)));
            DataColumn[] PrimaryKeyColumns = new DataColumn[1];
            PrimaryKeyColumns[0] = this.Columns["metabolite"];
            this.PrimaryKey = PrimaryKeyColumns;
            SortedDictionary<int, DataColumn> headers = new SortedDictionary<int, DataColumn>();
            foreach (var item in data.AsParallel().AsEnumerable().Select(x => x.ObservationPointId).Distinct().OrderBy(x => x))
            {
                DataColumn dc = this.Columns.Add(item.ToString(), typeof(Double));
                headers.Add(item, dc);
            }
            foreach (var item in data)
            {
                DataRow tmpRow = base.Rows.Find(item.MetaboliteId);
                if (tmpRow == null)
                {
                    tmpRow = base.Rows.Add(new object[] { item.MetaboliteId });
                    tmpRow["name"] = item.MetaboliteName;
                }
                tmpRow[headers[item.ObservationPointId]] = item.value;
            }
            this.AcceptChanges();
            _valueMax = data.AsParallel().AsUnordered().Max(x => x.value);
            _valueMin = data.AsParallel().AsUnordered().Min(x => x.value);
        }
        public HeatMapVisualisationDataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt) :
            base(info, ctxt)
        {
            _valueMin = (double)info.GetValue("valueMin", typeof(double));
            _valueMax = (double)info.GetValue("valueMax", typeof(double));
        }
        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)
        {
            base.GetObjectData(info, ctxt);
            info.AddValue("valueMin", _valueMin);
            info.AddValue("valueMax", _valueMax);
        }
    }

正如我可以通过读取构造函数HeatMapVisualisationDataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)SerializationInfo中的模式所观察到的那样,该表是正确的序列化的,并且就丝网化的 xml 模式而言,它来自"存储"。但是,查看此构造函数中的构造基类,用于序列化的所有类型为 double 的列现在都是 string 类型。我做错了什么?

更新 1:我还可以通过将数字数据类型从 double 更改为 floatdecimal 来重现此问题。类型 Guid 的主键列将反序列化为正确的类型。

更新2:在我看来,所描述的行为是一些DataTable.ReadXml()问题的后续,其中列的数据类型被字符串替换。

谢谢一月

子类化数据表在序列化/反序列化期间将数据类型信息从双精度更改为字符串

作为一种解决方案,通过绕过DataTable的序列化为XML,然后使用ReadXml从XML重新创建DataTable,我使用了这篇关于 ADO.NET 对象的二进制序列化的MSDN文章。诀窍是将有关列名和列类型的信息存储在一些额外的ArrayList中,并将其放入序列化中。在这里查看我当前的ISerializable接口实现:

public HeatMapVisualisationDataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)
    base()
{
    _valueMin = info.GetSingle("valueMin");
    _valueMax = info.GetSingle("valueMax");
    System.Collections.ArrayList colNames = (System.Collections.ArrayList)info.GetValue("colNames", typeof(System.Collections.ArrayList));
    System.Collections.ArrayList colTypes = (System.Collections.ArrayList)info.GetValue("colTypes", typeof(System.Collections.ArrayList));
    System.Collections.ArrayList dataRows = (System.Collections.ArrayList)info.GetValue("dataRows", typeof(System.Collections.ArrayList));
    // Add columns
    for (int i = 0; i < colNames.Count; i++)
    {
        DataColumn col = new DataColumn(colNames[i].ToString(), Type.GetType(colTypes[i].ToString()));
        this.Columns.Add(col);
    }
    // Add rows
    for (int i = 0; i < dataRows.Count; i++)
    {
        DataRow row = this.Rows.Add((object[])dataRows[i]);
    }
    this.AcceptChanges();
}
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)
{
    System.Collections.ArrayList colNames = new System.Collections.ArrayList();
    System.Collections.ArrayList colTypes = new System.Collections.ArrayList();
    System.Collections.ArrayList dataRows = new System.Collections.ArrayList();
    foreach (DataColumn col in this.Columns)
    {
        colNames.Add(col.ColumnName);
        colTypes.Add(col.DataType.FullName);
    }
    foreach (DataRow row in this.Rows)
    {
        dataRows.Add(row.ItemArray);
    }
    info.AddValue("colNames", colNames);
    info.AddValue("colTypes", colTypes);
    info.AddValue("dataRows", dataRows);
    info.AddValue("valueMin", _valueMin);
    info.AddValue("valueMax", _valueMax);
}

请注意,我不再调用 DataTable 的 GetObjectData(...) 和构造函数进行反序列化。但是,这不是我原始帖子的答案。这只是一种解决方法...所以"ReadXml()为什么要改变数据类型?"这个问题仍然悬而未决!