0

この質問の背景として、「作成されたコード」をにバインドしたいと思いDataTableますaspx:GridView。このテーブルを永続化するために、ISerializableインターフェイスを実装します。テーブルは正しく表示されますが、行を並べ替えるためのポストバックでInvalidCastExcpetionは、row.ItemArrayの要素がtypeからtypeに変更されたため、aがスローされdoubleますstring

これがクラスです。注:2つのコンストラクター。1つはDataTableを最初に構築するためのもので、もう1つは逆シリアル化プロセスでテーブルを構築するためのものです。

   [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);
        }
    }

SerializationInfoコンストラクターのでスキーマを読み取ることで確認できるようにHeatMapVisualisationDataTable(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext ctxt)、テーブルは正しくシリアル化されており、シリアル化されたxmlスキーマに関して「ストア」から正しく送信されています。ただし、このコンストラクターで構築された基本クラスを見ると、シリアル化前の型のすべての列が型になっていdoubleますstring。私は何が間違っているのですか?

更新1double :数値データ型をからfloatまたはに変更することでこの問題を再現することもできますdecimal。タイプの主キー列はGuid、正しいタイプに逆シリアル化されます。

更新2:私の意見では、説明されている動作は、DataTable.ReadXml()列のデータ型が文字列に置き換えられるいくつかの問題のフォローアップです。

ありがとう、1月

4

1 に答える 1

0

DataTable の XML へのシリアル化を回避し、続いて を使用して XML から DataTable を再作成することによる一種の解決策として、ADO.NET オブジェクトのバイナリ シリアル化に関する MSDN の記事ReadXmlを使用しました。秘訣は、列名と列タイプに関する情報をいくつかのエクストラに保存し、それらをシリアル化に入れることです。インターフェイスの現在の実装をここで参照してください。ArrayListISerializable

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);
}

GetObjectData(...)注:デシリアライゼーションのために DataTable とコンストラクターを呼び出さないことに注意してください。ただし、これは私の元の投稿に対する回答ではありません。それは単なる回避策です...だから、「なぜReadXml()DataTypesを変更するのですか?」という質問です。はまだ開いています!

于 2012-06-19T09:16:23.963 に答える