应用程序开发总结(8)--自定义序列化类

第十章 自定义序列化类

        按理说,这个内容应该是不值得来说的,因为已经存在很多的方法来对类进行序列化。即使是自定义的序列化,也存在很多的方法。我们最常见的就是通过xml的xmlserializer方式来序列化。也可以使用iSerializable这个接口来实现自动化的序列化。
       即使是手工来写序列化,每个人也会采用不同的方式。比如类xml的格式,或者json格式,还有其他的类似CSV键值对等。所谓CSV 是Comma Separated Value(逗号分隔值)的英文缩写,即记录通过逗号来把所有的属性值分割,解析的时候利用String.Split方法快速建立属性和值的关系。
        
         现在来简单的说明几种序列化可能存在的问题。
  • 使用xmlSerialize。优点,自动化实现。缺点,写一些xmlIngore,还要注意某些属性不能被序列化情况,还要类必须存在无参的构造函数。
  • 使用ISerialiable。优点,自动实现。缺点,某些字段要写一堆的Attribute。
  • 使用类似CSV的键值方式。优点,自己控制每一个字段的存储形式,比较灵活。缺点,需要对每一个属性进行编写代码。还要注意到分隔符的问题。

        现在我们要下面这个类,来进行字符方式的自定义序列化的演示。
 class HomeInfo
    {
        #region 属性
        public int StreetCode { get; set; }
        public string HomeName { get; set; }

        public PersonInfo Person { get; set; }
        #endregion

        #region 保存
        /// <summary>
        /// HomeInfo进行自定义序列化值
        /// </summary>
        /// <param name="splitChar"></param>
        /// <returns></returns>
        public string SerializeValue(char splitChar)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("StreetCode=" + StreetCode);
            sb.Append(splitChar);
            sb.Append("HomeName=" + HomeName);
            sb.Append(splitChar);


            sb.Append("Person=" + Person.SerializeValue(splitChar));

            return sb.ToString();
        }
        #endregion
    }
    class PersonInfo
    {
        #region 属性
        public string Name { get; set; }
        public int Age { get; set; }
        public string PersonProfile { get; set; }
        #endregion

        public string SerializeValue(char splitChar)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Name=" + Name); sb.Append(splitChar);
            sb.Append("Age=" + Age); sb.Append(splitChar);
            sb.Append("PersonProfile=" + PersonProfile); 
            return sb.ToString();
        }
    }
        由于类的属性的值千差万别,不能保证是否值中存在一些特殊字符串或者字符。所以在存储的时候我们对要存储的数据进行转义。比如我们打算用","来表示分割符,那么上面的程序得到的结果就会存在问题。因为无法区分HomeInfo和PersonInfo各自的逗号的位置。
       比如测试代码如下:
<pre name="code" class="csharp">public static void Test()
        {
            HomeInfo home = new HomeInfo();
            home.StreetCode = 10992;
            home.HomeName = "Tom's House";
            home.Person = new PersonInfo();

            home.Person.Age = 42;
            home.Person.Name = "Tomas jim";
            home.Person.PersonProfile = "出生在美国的德州,从小喜欢养鱼..爱好嘛..";

            string s = home.SerializeValue(',');
            //s="StreetCode=10992,HomeName=Tom's House,Person=Name=Tomas jim,Age=42,PersonProfile=出生在美国的德州,从小喜欢养鱼..爱好嘛..

            string[] strSplit = s.Split(',');
            //StreetCode=10992
            //HomeName=Tom's House
            //Person=Name=Tomas jim   -----从这开始解析就错误了
            //Age=42
            //PersonProfile=出生在美国的德州,从小喜欢养鱼..爱好嘛..
        }
 
 
     
      上面的问题出在属性中包含了类要使用的分隔符,在这里Person属性包含了HomeInfo类使用的分隔符“,”,从而导致属性值和本类的值无法区分。所以我们要做的是,如果属性中已经存在一个字符,那么这个字符不能在被上层类使用了。
      比如Person属性已经使用了",",那么HomeInfo就应该换一种风格符。要寻找可用的分隔符,可用先从特殊的可打印的字符开始。
char[] nSplitChars = new char[] { ';', ',', ':', '=', '&', '.', '|', '@', '#', '$', '%', '^', '*', '[', ']' };如果这些特殊的字符在属性中用到了,那么就开始使用通用字符'a~z‘,’A~Z','0~9';一般来说不可能把所有的字符都用到了,总会有一个合适的字符可用用来作为分隔符的。
     比如Person属性中使用,作为分隔符,HomeInfo使用;作为分隔符。
     由于定义的分隔符是查找出来的,所以必须在头部添加一个标签标明分隔符是什么。我会在最前面添加split:[具体的分隔符]来记录。
    
    我们重写下HomeInfo和PersonInfo的SerializeValue函数
/// <summary>
        /// HomeInfo进行自定义序列化值
        /// </summary>
        /// <returns></returns>
        public string SerializeValue()
        {
            List<string> s = new List<string>();
            s.Add("StreetCode=" + StreetCode);
            s.Add("HomeName=" + HomeName);
            s.Add("Person=" + Person.SerializeValue());

            return StringSplitHelper.FindSplitAndAppend(s);
        }
        
/// <summary>
        /// PersonInfo进行自定义序列化值
        /// </summary>
        /// <returns></returns>
        public string SerializeValue()
        {
            List<string> s = new List<string>();
            s.Add("Name=" + Name);
            s.Add("Age=" + Age);
            s.Add("PersonProfile=" + PersonProfile);
            return StringSplitHelper.FindSplitAndAppend(s);
        }

    其中StringSplitHelper类能够找到一个为使用的字符作为分隔符,并组合成一个字符串。得到的最后结果是

Split:&StreetCode=10992&HomeName=Tom's House&Person=Split:;Name=Tomas jim;Age=42;PersonProfile=出生在美国的德州,从小喜欢养鱼..爱好嘛..这个需要手工编辑下就可读了。

            //Split:&
            //StreetCode=10992&
            //HomeName=Tom's House&
            //Person=
            //      Split:;
            //           Name=Tomas jim;
            //           Age=42;
            //           PersonProfile=出生在美国的德州,从小喜欢养鱼..爱好嘛..
     上面的Person寻找到使用;使用分隔符,而HomeInfo使用&使用分隔符。由此,自定义方式的序列化类方式的问题解决。至于读,首先读头部的信息,获得分隔符,然后利用String.Split的方法获得属性和值的对。依次到属性,整个类的反序列化也就解决了。



        

猜你喜欢

转载自blog.csdn.net/htsitr2/article/details/38963597
今日推荐