none
序列化和反序列化一个继承DataTable的问题 RRS feed

  • 问题

  • 定义了一个DataTable类myTable,继承自DataTable。里面增加了一个自己的类,用来存放一些数据。定义如下:

        [Serializable()]
        public class myTable:DataTable
        {
            private UpdateParm _updateParm = new UpdateParm();
            public UpdateParm updateParm
            {
                get { return _updateParm; }
                set { _updateParm = value; }
            }

            public DataTableBase() :base(){ }

            protected DataTableBase(SerializationInfo info, StreamingContext context) : base(info, context)   { }
       }

    数据访问层中,从数据库检索数据到myTable1(myTable的一个实例)中,并且设置myTable1.updateParm.mytext="测试值"。mytext是UpdateParm 类的一个属性。

    序列化脚本如下,返回byte[]
                byte[] bArrayResult = null;
                myTable1.RemotingFormat = SerializationFormat.Binary;
                MemoryStream ms = new MemoryStream();
                IFormatter bf = new BinaryFormatter();
                bf.Serialize(ms, myTable1);
                bArrayResult = ms.ToArray();
                ms.Close();

    反序列化脚本:
                MemoryStream ms = new MemoryStream(bUserData);
                IFormatter bf = new BinaryFormatter();
                object obj = bf.Deserialize(ms);
                bTable = (myTable)obj;
                ms.Close();

    反序列化后,myTable1数据正常,但是myTable1.updateParm.mytext的值却没有传递成功,请帮忙分析一下是什么原因?

    2009年7月4日 6:06

答案

  • 由于DataTable实现了ISerializable接口,从而调用了自定义序列化机制。由于UpdateParm 是新的类型,肯定不为DataTable所识别故不序列化。
    具体步骤:1、重写GetObjectData方法;
                   2、为了支持匹配的反序列化,要提供一个反序列化构造函数MyTable(SerializationInfo info, StreamingContext context)。

    以下代码在vs2008上测试通过,支持UpdateParm的序列化和反序列化。代码请参考:

    [Serializable]
        public class MyTable : DataTable
        {
            private UpdateParm _updateParm = new UpdateParm();
            public UpdateParm updateParm
            {
                get { return _updateParm; }
                set { _updateParm = value; }
            }

            [OnSerializing]
            internal void OnSerializing(StreamingContext context)
            {
                string abc = "MyTable";
            }
            public MyTable() : base() { }

            public MyTable(SerializationInfo info, StreamingContext context):base(info,context)
            {
                updateParm = (UpdateParm)info.GetValue("updateParm",typeof(UpdateParm));
            }

            public override void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                base.GetObjectData(info, context); //保持对Table内的类型序列化
                info.AddValue("updateParm", updateParm, typeof(UpdateParm)); //新增对新类型支持
            }
        }
        [Serializable]
        public class UpdateParm
        {
            public string MyText { get; set; }

            [OnSerializing]
            internal void OnSerializing(StreamingContext context)
            {
                //默认情况下不进入该方法调用,说明没有对UpdateParm序列化
                //进行上述的两个步骤后,该事件被触发
                string abc = "UpdateParm";
            }
        }

    2009年7月4日 15:07

全部回复

  • 您好,UpdateParm类 也需要标记上[Serializable]特性,如果UpdateParm里还有自定义的类也需要标记。
    2009年7月4日 6:34
  • >UpdateParm类 也需要标记上[Serializable]特性
    已经标记了。
    2009年7月4日 6:45
  • 可否用文件来存储序列化对象?先看看用文件存有没有问题

    2009年7月4日 7:32
  • 或者也可以改二进制格式为xml,看看序列化时是否已为updateParm.mytext付值
    2009年7月4日 7:35
  • 我测试了一下,应该是序列化时就没有包括updateParm.mytext。
    这个类我单独序列化测试过,是没有问题的。

    2009年7月4日 8:18
  • 由于DataTable实现了ISerializable接口,从而调用了自定义序列化机制。由于UpdateParm 是新的类型,肯定不为DataTable所识别故不序列化。
    具体步骤:1、重写GetObjectData方法;
                   2、为了支持匹配的反序列化,要提供一个反序列化构造函数MyTable(SerializationInfo info, StreamingContext context)。

    以下代码在vs2008上测试通过,支持UpdateParm的序列化和反序列化。代码请参考:

    [Serializable]
        public class MyTable : DataTable
        {
            private UpdateParm _updateParm = new UpdateParm();
            public UpdateParm updateParm
            {
                get { return _updateParm; }
                set { _updateParm = value; }
            }

            [OnSerializing]
            internal void OnSerializing(StreamingContext context)
            {
                string abc = "MyTable";
            }
            public MyTable() : base() { }

            public MyTable(SerializationInfo info, StreamingContext context):base(info,context)
            {
                updateParm = (UpdateParm)info.GetValue("updateParm",typeof(UpdateParm));
            }

            public override void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                base.GetObjectData(info, context); //保持对Table内的类型序列化
                info.AddValue("updateParm", updateParm, typeof(UpdateParm)); //新增对新类型支持
            }
        }
        [Serializable]
        public class UpdateParm
        {
            public string MyText { get; set; }

            [OnSerializing]
            internal void OnSerializing(StreamingContext context)
            {
                //默认情况下不进入该方法调用,说明没有对UpdateParm序列化
                //进行上述的两个步骤后,该事件被触发
                string abc = "UpdateParm";
            }
        }

    2009年7月4日 15:07
  • By the way. 实例化MyTable时还是用不带参数的构造函数,不必理会MyTable(SerializationInfo info, StreamingContext context),这个构造函数是由.Net来调用的。故也可以将MyTable(SerializationInfo info, StreamingContext context)设计为Protected。以防止客户程序调用。
    2009年7月4日 17:14