C# 串行化与反串行化--自定义序列化

5、自定义序列化
如果你希望让用户对类进行串行化,但是对数据流的组织方式不完全满意,那么可以通过在自定义类中实现接口来自定义串行化行为。这个接口只有一个方法,GetObjectData.这个方法用于将对类对象进行串行化所需要的数据填进SerializationInfo对象。你使用的格式化器将构造SerializationInfo对象,然后在串行化时调用GetObjectData.如果类的父类也实现了ISerializable,那么应该调用GetObjectData的父类实现。
 
  如果你实现了ISerializable,那么还必须提供一个具有特定原型的构造器,这个构造器的参数列表必须与GetObjectData相同。这个构造器应该被声明为私有的或受保护的,以防止粗心的开发人员直接使用它。

public enum SexType
    {
        Male,
        Female
    }
    [Serializable()]
    public class Item
    {
        private int id;
        public int ID
        {
            get { return id; }
            set { id = value; }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Item() { } // 必须有默认构造函数,才能xml序列化
        public Item(int id, string name)
        {
            ID = id;
            Name = name;
        }

        public override string ToString()
        {
            return id.ToString() + "," + name;
        }

        public static Item ToObject(string str)
        {
            Item item = new Item();
            item.id = int.Parse(str.Split(',')[0]);
            item.name = str.Split(',')[1];
            return item;
        }
    }
    [Serializable()]
    public class ItemSub : Item
    {
        private SexType sex;
        public SexType Sex
        {
            get { return sex; }
            set { sex = value; }
        }

        public ItemSub() { } // 必须有默认构造函数,才能xml序列化
        public ItemSub(int id, string name, SexType sex)
            : base(id, name)
        {
            this.sex = sex;
        }
    }

    [Serializable()]
    public class ListBuffer : ISerializable
    {
        private List<string> list = new List<string>();

        public void Add(string str)
        {
            lock (list)
            {
                list.Add(str);
            }
        }

        public void Remove(string str)
        {
            lock (list)
            {
                list.Remove(str);
            }
        }

        public int Count
        {
            get { return list.Count; }
        }

        /// <summary>
        /// 自定义序列化方法
        /// 为了让子类能定义自定义序列化方法,这里必须标记为virtual
        /// 从接口中继承而来的方法没有任何修饰符,必须继承后自己添加
        /// 如果这个方法不标记为virtual,那么子类将不能重写自己的序列化方法
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public virtual void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            int index = 0;
            foreach (string str in list)
            {
                // 由于是列表,所以不能给每个对象分配一个固定的键名,所以这里用索引序号代替
                info.AddValue(index.ToString(), str);
                index++;
            }
        }

        public ListBuffer() { }
        protected ListBuffer(SerializationInfo info, StreamingContext ctxt)
        {
            int i = 0;
            SerializationInfoEnumerator irator = info.GetEnumerator();
            while (irator.MoveNext())
            {
                if (irator.Name.IndexOf("sub") == -1) // 这里先要过滤掉子类中添加的键名,否则会异常
                {
                    // 反序列化,从流中找到可用的键
                    object o = info.GetValue(i.ToString(), typeof(string));
                    if (o != null)
                        list.Add(o.ToString());
                }

                i++;
            }
        }
    }
    [Serializable()]
    public class ListBufferSub : ListBuffer
    {
        private List<Item> listItem = new List<Item>();

        public void AddItem(Item item)
        {
            lock (listItem)
            {
                listItem.Add(item);
            }
        }

        public void Remove(Item item)
        {
        }

        /// <summary>
        /// 子类要增加自己的序列化对象,必须重载基类的GetObjectData
        /// 再次重申一遍,基类从接口继承的GetObjectData默认不是virtual的,必须手动加上virtual修饰符
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public override void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            base.GetObjectData(info, ctxt); // 先调用基类的自定义序列化方法

            int index = base.Count; // 索引序号从基类的索引序号开始
            foreach (Item item in listItem) // 然后再将子类自己的序列化成员添加到序列流中
            {
                info.AddValue("sub"+index.ToString(), item);
                index++;
            }
        }

        public ListBufferSub() { }
        protected ListBufferSub(SerializationInfo info, StreamingContext ctxt)
            : base(info, ctxt) // 先调用基类的反序列化构造方法(序列化流中包含基类和子类的键,在使用是要注意剔除)
        {
            int i = 0;
            SerializationInfoEnumerator irator = info.GetEnumerator();
            while (irator.MoveNext())
            {
                if (irator.Name.IndexOf("sub") != -1) // 找到子类的键
                {
                    object o = info.GetValue("sub" + i.ToString(), typeof(Item)); // 获得子类的对象
                    if (o != null && o is Item)
                        listItem.Add(o as Item);
                }
                i++;
            }
        }
    }

    [Serializable()]
    public class BinarySerialize
    {
        private int id;
        public int ID
        {
            get { return id; }
            set { id = value; }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private SexType sex;
        public SexType Sex
        {
            get { return sex; }
            set { sex = value; }
        }

        private List<string> listStr;
        public List<string> ListStr
        {
            get { return listStr; }
            set { listStr = value; }
        }

        private List<Item> listItem;
        public List<Item> ListItem
        {
            get { return listItem; }
            set { listItem = value; }
        }

        private ListBuffer buffer = new ListBuffer();
        public ListBuffer Buffer
        {
            get { return buffer; }
            set { buffer = value; }
        }

        private ListBufferSub bufferSub = new ListBufferSub();
        public ListBufferSub BufferSub
        {
            get { return bufferSub; }
            set { bufferSub = value; }
        }

        private List<ListBuffer> listBuffer;
        public List<ListBuffer> ListBuffer
        {
            get { return listBuffer; }
            set { listBuffer = value; }
        }
    }

    public sealed class ConfigurationManagerBinarySerialize
    {
        private static string path = System.Windows.Forms.Application.StartupPath + "\\BinarySerialize.bat";

        public static BinarySerialize Get()
        {
            if (!File.Exists(path))
                return null;

            BinaryFormatter b = new BinaryFormatter();
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                return (BinarySerialize)b.Deserialize(fs);
            }
        }

        public static void Set(BinarySerialize hr)
        {
            BinaryFormatter b = new BinaryFormatter();
            using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
            {
                b.Serialize(fs, hr);
            }
        }
    }

备注:

这里写了一个很复杂的自定义序列化的例子,其中包含集合,继承等关系。

对于需要自定义序列化的类,需要使其继承ISerializable接口,实现GetObjectData函数以及添加一个带相同参数的构造函数。

序列化时,系统调用GetObjectData保存信息,反序列化时,系统调用带参数的构造函数创建对象。

如果基类自定义了序列化,那么子类在自定义序列化方法时首先要调用基类的自定义方法,然后再进行自己的序列化操作。

基类的GetObjectData方法必须注明是virtual的,否则子类无法正常序列化。

自定义序列化必须使用BinaryFormatter进行序列化操作,xml无法正常工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值