见面和流3,类别化和反类别

       
二进制连串化可以方便赶快的将目的开始展览持久化恐怕互连网传输,并且容积小、质量高,应用面乃至还要高于json的连串化;发轫此前,先来看望dotcore/dotne自带的2进制类别化:C#中目标系列化和反连串化一般是经过BinaryFormatter类来达成的贰进制类别化、反连串化的。

3、流和系列化

一.对象类别化的牵线

系列化正是把二个对象产生流的样式,方便传输和还原。四弟不才,总结下对二进制体系化和Json系列化的使用:

        BinaryFormatter序列化:

三.一 流概念及.NET中常见流

  无论什么信息,文字,声音,图像,只要进入了计算机就都被转化为数字,以数字方式运算、存储。由于计算机中使用二进制运算,因此数字只有两个:0 与 1,就是逢 2 进位。所以说最终形式都是一连串的类似00010010101101001111001这样的二进制数据。

  要把一片二进制数据逐一输出到某个设备中或从某个设备逐一读取一片二进制数据,不管输入输出设备是什么,我们要用统一的方式来完成这些操作,用一种抽象的方式进行描述,这个抽象描述方式起名为IO流,对应的抽象类为OutputStream和InputStream,不同的实现类就代表不同的输入和输出设备,它们都是针对字节进行操作的。
    
  计算机中的一切都是二进制的字节形式存在。对于“中国”这些字符,首先要得到其对应的字节,然后将字节写入到输出流。读取时,首先读到的是字节,可是我们要把它显示为字符,需要将字节转换成字符。

  字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向IO设别写入或读取字符串提供了一点点方便。

  字符向字节转换时,要注意编码的问题,因为字符串转成字节数组其实是转成该字符的某种编码的字节形式,读取也是反之的道理!!

   实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图所示。

 

  常见的流类型包罗:文本流、终端操作流及互联网Socket等,在.NET中,System.IO.Stream类型被规划为作为具有流类型的虚基类,当必要自定义1种流类型时也应当直接大概直接地承接自Stream类型。下图体现了在.NET青海中国广播公司泛的流类型以及它们的项目结构:

亚洲必赢手机入口 1

  从上海教室中能够发掘,Stream类型承接自MarshalByRefObject类型,那保障了流类型能够超过应用程序域进行交互

  下边包车型客车代码中显得了怎么着在.NET中采纳FileStream文件流进行简单的文件读写操作:

亚洲必赢手机入口 2亚洲必赢手机入口 3

    class Program
    {
        private const int bufferlength = 1024;

        static void Main(string[] args)
        {
            //创建一个文件,并写入内容
            string filename = @"C:\TestStream.txt";
            string filecontent = GetTestString();

            try
            {
                if (File.Exists(filename))
                {
                    File.Delete(filename);
                }

                // 创建文件并写入内容
                using (FileStream fs = new FileStream(filename, FileMode.Create))
                {
                    Byte[] bytes = Encoding.UTF8.GetBytes(filecontent);
                    fs.Write(bytes, 0, bytes.Length);
                }

                // 读取文件并打印出来
                using (FileStream fs = new FileStream(filename, FileMode.Open))
                {
                    Byte[] bytes = new Byte[bufferlength];
                    UTF8Encoding encoding = new UTF8Encoding(true);
                    while (fs.Read(bytes, 0, bytes.Length) > 0)
                    {
                        Console.WriteLine(encoding.GetString(bytes));
                    }
                }
                // 循环分批读取打印
                //using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
                //{
                //    Byte[] bytes = new Byte[bufferlength];
                //    int bytesRead;
                //    do
                //    {
                //        bytesRead = fs.Read(bytes, 0, bufferlength);
                //        Console.WriteLine(Encoding.UTF8.GetString(bytes, 0, bytesRead));
                //    } while (bytesRead > 0);
                //}
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }

        // 01.取得测试数据
        static string GetTestString()
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < 10; i++)
            {
                builder.Append("我是测试数据\r\n");
                builder.Append("我是长江" + (i + 1) + "号\r\n");
            }
            return builder.ToString();
        }
    }

View Code

  上述代码的推行结果如下图所示:

      亚洲必赢手机入口 4

  在实质上付出中平常会遇上要求传递一个比比较大的文书,也许事先不或者得知文件大小,由此也就无法创设2个尺码正好适合的Byte[]数组,此时不得不分批读取和写入历次只读取部分字节,直到文件尾。比如大家须求复制G盘中二个尺寸为四.肆MB的mp三文书到C盘中去,纵然大家对大小超越二MB的文书都采用分批读取写入机制,能够透过如下代码达成:

亚洲必赢手机入口 5亚洲必赢手机入口 6

    class Program
    {
        private const int BufferSize = 10240; // 10 KB
        public static void Main(string[] args)
        {
            string fileName = @"G:\My Musics\BlueMoves.mp3"; // Source 4.4 MB
            string copyName = @"C:\BlueMoves-Copy.mp3"; // Destination 4.4 MB
            using (Stream source = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                using (Stream target = new FileStream(copyName, FileMode.Create, FileAccess.Write))
                {
                    byte[] buffer = new byte[BufferSize];
                    int bytesRead;
                    do
                    {
                        // 从源文件中读取指定的10K长度到缓存中
                        bytesRead = source.Read(buffer, 0, BufferSize);
                        // 从缓存中写入已读取到的长度到目标文件中
                        target.Write(buffer, 0, bytesRead);
                    } while (bytesRead > 0);
                }
            }
            Console.ReadKey();
        }
    }

View Code

  上述代码中,设置了缓存buffer大小为拾K,即每一次只读取十K的内容长度到buffer中,通过轮回的高频读写和写入落成整个复制操作。

(一).NET援助对象类别化的二种格局

一.第贰,2进制连串化(BinaryFormatter)供给要系列化的类必须是可体系化的(即在类定义的前面加塞里alizable关键字),而且它的父类类型也务必是可连串化的,经过查阅开掘,Dotnet中诸多体系和结构都有其1符号;而Json系列化不用写标志;

1 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
2 
3 System.IO.MemoryStream memStream = new System.IO.MemoryStream();
4 
5 serializer.Serialize(memStream, request);

三.2 怎么样利用压缩流?

  NET中提供了对于减弱和平化解压的支撑:GZipStream类型和DeflateStream类型,位于System.IO.Compression取名空间下且都接二连三于Stream类型

    对文件减弱的真面目实际上是本着字节的操作,也属于1种流操作

  上边包车型客车代码展现了GZipStream的应用格局,DeflateStream和GZipStream的采纳办法差不离完全1致:

亚洲必赢手机入口 7亚洲必赢手机入口 8

    class Program
    {
        // 缓存数组的长度
        private const int bufferSize = 1024;

        static void Main(string[] args)
        {
            string test = GetTestString();
            byte[] original = Encoding.UTF8.GetBytes(test);
            byte[] compressed = null;
            byte[] decompressed = null;
            Console.WriteLine("数据的原始长度是:{0}", original.LongLength);
            // 1.进行压缩
            // 1.1 压缩进入内存流
            using (MemoryStream target = new MemoryStream())
            {
                using (GZipStream gzs = new GZipStream(target, CompressionMode.Compress, true))
                {
                    // 1.2 将数据写入压缩流
                    WriteAllBytes(gzs, original, bufferSize);
                }
                compressed = target.ToArray();
                Console.WriteLine("压缩后的数据长度:{0}", compressed.LongLength);
            }
            // 2.进行解压缩
            // 2.1 将解压后的数据写入内存流
            using (MemoryStream source = new MemoryStream(compressed))
            {
                using (GZipStream gzs = new GZipStream(source, CompressionMode.Decompress, true))
                {
                    // 2.2 从压缩流中读取所有数据
                    decompressed = ReadAllBytes(gzs, bufferSize);
                }
                Console.WriteLine("解压后的数据长度:{0}", decompressed.LongLength);
                Console.WriteLine("解压前后是否相等:{0}", test.Equals(Encoding.UTF8.GetString(decompressed)));
            }
            Console.ReadKey();
        }

        // 01.取得测试数据
        static string GetTestString()
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < 10; i++)
            {
                builder.Append("我是测试数据\r\n");
                builder.Append("我是长江" + (i + 1) + "号\r\n");
            }
            return builder.ToString();
        }

        // 02.从一个流总读取所有字节
        static Byte[] ReadAllBytes(Stream stream, int bufferlength)
        {
            Byte[] buffer = new Byte[bufferlength];
            List<Byte> result = new List<Byte>();
            int read;
            while ((read = stream.Read(buffer, 0, bufferlength)) > 0)
            {
                if (read < bufferlength)
                {
                    Byte[] temp = new Byte[read];
                    Array.Copy(buffer, temp, read);
                    result.AddRange(temp);
                }
                else
                {
                    result.AddRange(buffer);
                }
            }
            return result.ToArray();
        }

        // 03.把字节写入一个流中
        static void WriteAllBytes(Stream stream, Byte[] data, int bufferlength)
        {
            Byte[] buffer = new Byte[bufferlength];
            for (long i = 0; i < data.LongLength; i += bufferlength)
            {
                int length = bufferlength;
                if (i + bufferlength > data.LongLength)
                {
                    length = (int)(data.LongLength - i);
                }
                Array.Copy(data, i, buffer, 0, length);
                stream.Write(buffer, 0, length);
            }
        }
    }

View Code

  上述代码的运行结果如下图所示:

  亚洲必赢手机入口 9

  须要专注的是:动用 GZipStream 类压缩大于 肆 GB 的公文时将会引发那些

  通过GZipStream的构造方法能够看到,它是四个特出的Decorator装饰者方式的选择,所谓装饰者方式,就是动态地给一个对象加多一些极度的职务。对于扩大新职能那些方面,装饰者形式比新扩张四个子类更为灵活。就拿地点代码中的GZipStream来讲,它扩充的是MemoryStream,为Write方法扩充了压缩的成效,从而实现了削减的利用。

亚洲必赢手机入口 10

扩展:过多材质评释.NET提供的GZipStream和DeflateStream类型的压缩算法并不完美,也无法调动压缩率,某个第二方的组件比方夏普ZipLib完毕了更迅捷的缩减和平消除压算法,大家可以在nuget中为项目增多该零件。

亚洲必赢手机入口 11

2进制体系化:对象系列化之后是贰进制格局的,通过BinaryFormatter类来达成的,这些类位于System.Runtime.Serialization.Formatters.Binary命名空间下。

二.要是类中一些品质不希望被二进制连串化,加Non塞里alized关键字就可以,而要2进制体系化的习性的品类必须是可种类化的数据类型;

        BinaryFormatter反连串化:

3.三 Serializable个性有啥意义?

  通过地方的流类型能够方便地操作各样字节流,不过什么把现存的实例对象转变为便于传输的字节流,就要求使用种类化才具。目的实例的连串化,是指将实例对象调换为可便宜存款和储蓄、传输和互动的流。在.NET中,通过Serializable特点提供了连串化对象实例的编写制定,当一个品类被发明为Serializable后,它就能被诸如BinaryFormatter等落到实处了IFormatter接口的体系举行系列化和反体系化。

    [Serializable]
    public class Person
    {
        ......
    }

  可是,在事实上支出中大家会碰着对于部分尤其的不指望被类别化的分子,那时我们得感到有个别成员增多NonSerialized特点。举例,有如下代码所示的三个Person类,当中number代表学号,name代表姓名,大家不期待name被系列化,于是可感到name增加NonSerialized特性:

亚洲必赢手机入口 12亚洲必赢手机入口 13

    class Program
    {
        static void Main(string[] args)
        {
            Person obj = new Person(26, "Edison Chou");
            Console.WriteLine("初始状态:");
            Console.WriteLine(obj);

            // 序列化对象
            byte[] data = Serialize(obj);
            // 反序列化对象
            Person newObj = DeSerialize(data);

            Console.WriteLine("经过序列化和反序列化后:");
            Console.WriteLine(newObj);

            Console.ReadKey();
        }

        // 序列化对象
        static byte[] Serialize(Person p)
        {
            // 使用二进制序列化
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, p);
                return ms.ToArray();
            }
        }

        // 反序列化对象
        static Person DeSerialize(byte[] data)
        {
            // 使用二进制反序列化
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data))
            {
                Person p = formatter.Deserialize(ms) as Person;
                return p;
            }
        }
    }

View Code

  上述代码的运营结果如下图所示:

  亚洲必赢手机入口 14

注意:当2个基类使用了Serializable天性后,并不表示其颇具子类都能被连串化。事实上,我们不能够不为各样子类都增添Serializable特性本事确定保证其能被科学地种类化。

SOAP序列化:对象体系化之后的结果符合SOAP协议,相当于足以经过SOAP 协议传输,通过System.Runtime.Serialization.Formatters.Soap命名空间下的SoapFormatter类来兑现的。

三.二进制类别化只会对类中的字段(属性)体系化,故类别化时不提出使用自动属性(每趟更动的字段都或者不雷同,影响反类别化)。

 1  memStream.Position=0;
 2 
 3  System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializer =
 4 
 5  new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
 6 
 7  object newobj = deserializer.Deserialize(memStream);
 8 
 9  memStream.Close();
10 
11  return newobj;

三.四 .NET提供了哪三种可开始展览系列化操作的体系?

  我们早已知晓了什么把2个类型表明为可体系化的品种,但是万里长征只走了第二步,具体做到类别化和反类别化的操作还索要两个施行这几个操作的档期的顺序。为了连串化具体实例到某种专用的格式,.NET中提供了二种对象体系格式化类型:BinaryFormatterSoapFormatterXmlSerializer

  (1)BinaryFormatter

  顾名思义,BinaryFormatter可用于将可种类化的靶子类别化成二进制的字节流,在头里Serializable性情的代码示例中早就展现过,那里不再重复体现。

  (2)SoapFormatter

  SoapFormatter从事于将可体系化的品类类别化成适合SOAP标准的XML文书档案以供役使。在.NET中,要利用SoapFormatter需求先增添对于SoapFormatter的引用:

using System.Runtime.Serialization.Formatters.Soap;

Tips:SOAP是一种位于应用层的网络协议,它根据XML,并且是Web
Service的骨干协议。

  (3)XmlSerializer

  XmlSerializer并不仅针对那么些标志了Serializable天性的花色,更为须求留意的是,Serializable和NonSerialized个性在XmlSerializer类型对象的操作中完全不起功效,取代他的是XmlIgnore质量。XmlSerializer能够对未有标志塞里alizable天性的品种对象进行体系化,但是它照旧有肯定的范围:

  ①
使用XmlSerializer类别化的目的必须出示地具有2个无参数的公共构造方法见面和流3,类别化和反类别。;

  由此,大家需求修改前边代码示例中的Person类,加多一个无参数的国有构造方法:

    [Serializable]
    public class Person
    {
        ......
        public Person()
        {
        }
        ......
    }

  ② XmlSerializer只可以体系化公共成员变量

  由此,Person类中的私有成员_number便无法被XmlSerializer进行类别化:

    [Serializable]
    public class Person
    {
        // 私有成员无法被XmlSerializer序列化
        private int _number;
    }

  (4)综合示范SoapFormatter和XmlSerializer的接纳方式:

  一重新改写Person类

亚洲必赢手机入口 15亚洲必赢手机入口 16

    [Serializable]
    public class Person
    {
        // 私有成员无法被XmlSerializer序列化
        private int _number;
        // 使用NonSerialized特性标记此成员不可被BinaryFormatter和SoapFormatter序列化
        [NonSerialized]
        public string _name;
        // 使用XmlIgnore特性标记此成员不可悲XmlSerializer序列化
        [XmlIgnore]
        public string _univeristy;

        public Person()
        {
        }

        public Person(int i, string s, string u)
        {
            this._number = i;
            this._name = s;
            this._univeristy = u;
        }

        public override string ToString()
        {
            string result = string.Format("学号是:{0},姓名是:{1},大学是:{2}", _number, _name, _univeristy);
            return result;
        }
    }

View Code

  二新添SoapFormatter和XmlSerializer的种类化和反类别化方法

亚洲必赢手机入口 17亚洲必赢手机入口 18

    #region 01.SoapFormatter
    // 序列化对象-SoapFormatter
    static byte[] SoapFormatterSerialize(Person p)
    {
        // 使用Soap协议序列化
        IFormatter formatter = new SoapFormatter();
        using (MemoryStream ms = new MemoryStream())
        {
            formatter.Serialize(ms, p);
            return ms.ToArray();
        }
    }

    // 反序列化对象-SoapFormatter
    static Person SoapFormatterDeSerialize(byte[] data)
    {
        // 使用Soap协议反序列化
        IFormatter formatter = new SoapFormatter();
        using (MemoryStream ms = new MemoryStream(data))
        {
            Person p = formatter.Deserialize(ms) as Person;
            return p;
        }
    } 
    #endregion

    #region 02.XmlSerializer
    // 序列化对象-XmlSerializer
    static byte[] XmlSerializerSerialize(Person p)
    {
        // 使用XML规范序列化
        XmlSerializer serializer = new XmlSerializer(typeof(Person));
        using (MemoryStream ms = new MemoryStream())
        {
            serializer.Serialize(ms, p);
            return ms.ToArray();
        }
    }

    // 反序列化对象-XmlSerializer
    static Person XmlSerializerDeSerialize(byte[] data)
    {
        // 使用XML规范反序列化
        XmlSerializer serializer = new XmlSerializer(typeof(Person));
        using (MemoryStream ms = new MemoryStream(data))
        {
            Person p = serializer.Deserialize(ms) as Person;
            return p;
        }
    } 
    #endregion

View Code

  叁改写Main方法进行测试

亚洲必赢手机入口 19亚洲必赢手机入口 20

    static void Main(string[] args)
    {
        Person obj = new Person(26, "Edison Chou", "CUIT");
        Console.WriteLine("原始对象为:");
        Console.WriteLine(obj.ToString());

        // 使用SoapFormatter序列化对象
        byte[] data1 = SoapFormatterSerialize(obj);
        Console.WriteLine("SoapFormatter序列化后:");
        Console.WriteLine(Encoding.UTF8.GetString(data1));
        Console.WriteLine();
        // 使用XmlSerializer序列化对象
        byte[] data2 = XmlSerializerSerialize(obj);
        Console.WriteLine("XmlSerializer序列化后:");
        Console.WriteLine(Encoding.UTF8.GetString(data2));

        Console.ReadKey();
    }

View Code

  示例运转结果如下图所示:

亚洲必赢手机入口 21

XML序列化:对象系列化之后的结果是XML格局的,通过XmlSerializer 类来促成的,那个类位于System.Xml.塞里alization命名空间下。XML种类化不能够系列化私有数量。

上边是贰进制系列化的代码:

     
  用着多了就开掘BinaryFormatter有多数地点不妥,下边就来数数这几个系列化的“三宗罪”:

三.伍 怎么着自定义体系化和反类别化的历程?

  对于有个别类型,体系化和反体系化往往有部分新鲜的操作或逻辑检查供给,那时就要求大家能够主动地垄断(monopoly)连串化和反连串化的经过。.NET中提供的Serializable本性帮助大家越发急速地表达了2个可类别化的档案的次序(因而也就缺失了灵活性),但过多时候是因为专门的学业逻辑的供给,大家必要积极地调整连串化和反体系化的经过。由此,.NET提供了ISerializable接口来知足自定义类别化须要。

   上面包车型大巴代码展示了自定义种类化和反种类化的品类模板:

    [Serializable]
    public class MyObject : ISerializable
    {
        protected MyObject(SerializationInfo info, StreamingContext context)
        {
            // 在此构造方法中实现反序列化
        }

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            // 在此方法中实现序列化
        }
    }

  如上代码所示,GetObjectData和异样构造方法都吸收三个参数:SerializationInfo
类型参数的作用类似于1个哈希表,通过key/value对来囤积整个对象的剧情,而StreamingContext
类型参数则含有了流的此时此刻事态,大家得以依照此参数来推断是还是不是须要体系化和反种类化类型独享。

  借使基类实现了ISerializable接口,则派生类须求针对本人的成员贯彻反系列化构造方法,并且重写基类中的GetObjectData方法。

亚洲必赢手机入口 ,  下边通过二个实际的代码示例,来打探什么在.NET程序中自定义体系化和反种类化的进程:

  一率先我们须求贰个必要被系列化和反体系化的门类,该项目有非常的大大概被其余项目承袭

亚洲必赢手机入口 22亚洲必赢手机入口 23

    [Serializable]
    public class MyObject : ISerializable
    {
        private int _number;
        [NonSerialized]
        private string _name;

        public MyObject(int num, string name)
        {
            this._number = num;
            this._name = name;
        }

        public override string ToString()
        {
            return string.Format("整数是:{0}\r\n字符串是:{1}", _number, _name);
        }

        // 实现自定义的序列化
        protected MyObject(SerializationInfo info, StreamingContext context)
        {
            // 从SerializationInfo对象(类似于一个HashTable)中读取内容
            this._number = info.GetInt32("MyObjectInt");
            this._name = info.GetString("MyObjectString");
        }

        // 实现自定义的反序列化
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            // 将成员对象写入SerializationInfo对象中
            info.AddValue("MyObjectInt", this._number);
            info.AddValue("MyObjectString", this._name);
        }
    }

View Code

  贰随之编写1个接续自MyObject的子类,并丰硕八个私人住房的成员变量。要求留意的是:子类必须负担体系化和反连串化自身丰盛的分子变量

亚洲必赢手机入口 24亚洲必赢手机入口 25

    [Serializable]
    public class MyObjectSon : MyObject
    {
        // 自己添加的成员
        private string _sonName;

        public MyObjectSon(int num, string name)
            : base(num, name)
        {
            this._sonName = name;
        }

        public override string ToString()
        {
            return string.Format("{0}\r\n之类字符串是:{1}", base.ToString(), this._sonName);
        }

        // 实现自定义反序列化,只负责子类添加的成员
        protected MyObjectSon(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            this._sonName = info.GetString("MyObjectSonString");
        }

        // 实现自定义序列化,只负责子类添加的成员
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("MyObjectSonString", this._sonName);
        }
    }

View Code

  叁最终编写Main方法,测试自定义的类别化和反连串化

亚洲必赢手机入口 26亚洲必赢手机入口 27

    class Program
    {
        static void Main(string[] args)
        {
            MyObjectSon obj = new MyObjectSon(10086, "Edison Chou");
            Console.WriteLine("初始对象为:");
            Console.WriteLine(obj.ToString());
            // 序列化
            byte[] data = Serialize(obj);
            Console.WriteLine("经过序列化与反序列化之后:");
            Console.WriteLine(DeSerialize(data));

            Console.ReadKey();
        }

        // 序列化对象-BinaryFormatter
        static byte[] Serialize(MyObject p)
        {
            // 使用二进制序列化
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, p);
                return ms.ToArray();
            }
        }

        // 反序列化对象-BinaryFormatter
        static MyObject DeSerialize(byte[] data)
        {
            // 使用二进制反序列化
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data))
            {
                MyObject p = formatter.Deserialize(ms) as MyObject;
                return p;
            }
        }
    }

View Code

  上述代码的周转结果如下图所示:

      亚洲必赢手机入口 28

  从结果图中能够看看,由于达成了自定义的系列化和反种类化,从而原先使用Serializable特性的私下认可类别化和反体系化算法没有起功效,MyObject类型的持有成员通过类别化和反类别化之后均被全体地还原了,包蕴注解了NonSerialized特性的积极分子。

(二)二种序列化的差距

一.要系列化的类的概念:

     
  壹.类名位置要增加[Serializable],不加不给系列化;平常的用法应该是种类化贰个目的,不需的地点加上NonSerialized才合理吗;

二进制格式和SOAP格式可种类化2个品类的全部可类别化字段,不管它是公私字段依旧私有字段。XML格式仅能系列化公共字段或持有公共性质的个人字段,未经过品质公开的个人字段将被忽视。

亚洲必赢手机入口 29亚洲必赢手机入口 30

     
  2.序列化byte[]结果丰盛大,使用System.Text.Encoding.UTF八.GetString(bytes)查看下,开采在这之中有一大堆的元数据;比较看看google的protobuf,pb为何在网络上运用的尤其多,那和她作者连串化完后体量小有着绝大部门的来头;

选取2进制格式体系化时,它不可是将目的的字段数据开始展览持久化,也持久化各样项目的一点一滴限定名称和定义程序集的全体名称(包蕴包称、版本、公钥标识、区域性),那么些多少驱动在拓展二进制格式反体系化时亦会进展项目检查。SOAP格式种类化通过动用XML命名空间来持久化原始程序集音讯。而XML格式系列化不会保留完好的门类名称或程序集音信。那便利XML数据表现形式更有终点开放性。若是愿意尽大概延长持久化对象图的利用限制时,SOAP格式和XML格式是顶级采纳。

  1  [Serializable]
  2     public class Person
  3     {
  4         private string _sName;
  5 
  6         public string SName
  7         {
  8             get { return _sName; }
  9             set { _sName = value; }
 10         }
 11 
 12         private int _iAge;
 13 
 14         public int IAge
 15         {
 16             get { return _iAge; }
 17             set { _iAge = value; }
 18         }
 19 
 20         private string _sEmail;
 21 
 22         public string SEmail
 23         {
 24             get { return _sEmail; }
 25             set { _sEmail = value; }
 26         }
 27 
 28         private string _sPhone;
 29 
 30         public string SPhone
 31         {
 32             get { return _sPhone; }
 33             set { _sPhone = value; }
 34         }
 35 
 36         private string _sAddress;
 37 
 38         public string SAddress
 39         {
 40             get { return _sAddress; }
 41             set { _sAddress = value; }
 42         }
 43 
 44         private string _sSex;
 45 
 46         public string SSex
 47         {
 48             get { return _sSex; }
 49             set { _sSex = value; }
 50         }
 51 
 52         private Car _myCar;
 53 
 54         public Car MyCar
 55         {
 56             get { return _myCar; }
 57             set { _myCar = value; }
 58         }
 59 
 60         public Person()
 61         {
 62 
 63         }
 64 
 65         public Person(string name,int age,string sex,string email,string phone,string address,Car car):this()
 66         {
 67             this.SName = name;
 68             this.IAge = age;
 69             this.SSex = sex;
 70             this.SEmail = email;
 71             this.SPhone = phone;
 72             this.SAddress = address;
 73             this.MyCar = car;
 74         }
 75     }
 76     [Serializable]
 77     public class Car
 78     {
 79         private string _sCarType;
 80 
 81         public string SCarType
 82         {
 83             get { return _sCarType; }
 84             set { _sCarType = value; }
 85         }
 86 
 87         private string _sCarNum;
 88 
 89         public string SCarNum
 90         {
 91             get { return _sCarNum; }
 92             set { _sCarNum = value; }
 93         }
 94 
 95         public Car()
 96         {
 97 
 98         }
 99 
100         public Car(string carType,string carNum):this()
101         {
102             this.SCarType = carType;
103             this.SCarNum = carNum;
104         }
105     }

     
  叁.系列化对象急需完全1致,连类的命名空间都要平等,这一点对于分面式开辟的选取来讲也是不可接受的;

(三)使用性格对系列化的操纵

View Code

     
  既然BinaryFormatter倒霉用,那就不得不出手动和自动行落成壹个减轻上述难点的二进制连串化方案;首先排除[Serializable]本条标签,接着主借使分析对象,并定义对象类别化后的数据结构;那里的主见是按长度加内容的点子来定义,举例:使用int作为长度,来保存3个int值,体系化完应该是:四,0,0,0,1,0,0,0那样的一组bytes,同理能够将int、short、long、float、double、datetime、enum、array、string、class、generic等依照这些格式实行类别化,这里最首要采取的是BitConverter、反射等来实现连串化与反系列化;

要让1个目的帮衬.Net连串化服务,用户必须为每种关联的类拉长[Serializable]特点。假设类中微微成员不切合参预类别化(举例:密码字段),能够在这几个域前增进[NonSerialized]特性。

二.二进制连串化代码:

        种类化达成如下:

二.使用2进制类别化和反类别化

亚洲必赢手机入口 31亚洲必赢手机入口 32

亚洲必赢手机入口 33亚洲必赢手机入口 34

(壹)2进制类别化与反系列化的先后示例

BinaryFormatter bf = new BinaryFormatter();
            Person p = null;

            using (FileStream fsWrite=new FileStream("person.bin",FileMode.Create,FileAccess.Write))
            {
                if (ckbIsCar.Checked)
                {
                    var strCarNum = txtCarNum.Text.Trim();
                    var strCarType = txtCarType.Text.Trim();

                    Car c1=new Car(strCarType,strCarNum);
                    p = new Person(strName, intAge,strSex, strEmail, strPhone, strAddress, c1);
                }
                else
                {
                    //不登记车的情况
                    p = new Person(strName, intAge,strSex, strEmail, strPhone, strAddress, null);
                }
                //二进制序列化
                bf.Serialize(fsWrite, p);
                MessageBox.Show("对象序列化完毕");
  1         public static byte[] Serialize(object param)
  2         {
  3             List<byte> datas = new List<byte>();
  4 
  5             var len = 0;
  6 
  7             byte[] data = null;
  8 
  9             if (param == null)
 10             {
 11                 len = 0;
 12             }
 13             else
 14             {
 15                 if (param is string)
 16                 {
 17                     data = Encoding.UTF8.GetBytes((string)param);
 18                 }
 19                 else if (param is byte)
 20                 {
 21                     data = new byte[] { (byte)param };
 22                 }
 23                 else if (param is bool)
 24                 {
 25                     data = BitConverter.GetBytes((bool)param);
 26                 }
 27                 else if (param is short)
 28                 {
 29                     data = BitConverter.GetBytes((short)param);
 30                 }
 31                 else if (param is int)
 32                 {
 33                     data = BitConverter.GetBytes((int)param);
 34                 }
 35                 else if (param is long)
 36                 {
 37                     data = BitConverter.GetBytes((long)param);
 38                 }
 39                 else if (param is float)
 40                 {
 41                     data = BitConverter.GetBytes((float)param);
 42                 }
 43                 else if (param is double)
 44                 {
 45                     data = BitConverter.GetBytes((double)param);
 46                 }
 47                 else if (param is DateTime)
 48                 {
 49                     var str = "wl" + ((DateTime)param).Ticks;
 50                     data = Encoding.UTF8.GetBytes(str);
 51                 }
 52                 else if (param is Enum)
 53                 {
 54                     var enumValType = Enum.GetUnderlyingType(param.GetType());
 55 
 56                     if (enumValType == typeof(byte))
 57                     {
 58                         data = new byte[] { (byte)param };
 59                     }
 60                     else if (enumValType == typeof(short))
 61                     {
 62                         data = BitConverter.GetBytes((Int16)param);
 63                     }
 64                     else if (enumValType == typeof(int))
 65                     {
 66                         data = BitConverter.GetBytes((Int32)param);
 67                     }
 68                     else
 69                     {
 70                         data = BitConverter.GetBytes((Int64)param);
 71                     }
 72                 }
 73                 else if (param is byte[])
 74                 {
 75                     data = (byte[])param;
 76                 }
 77                 else
 78                 {
 79                     var type = param.GetType();
 80 
 81 
 82                     if (type.IsGenericType || type.IsArray)
 83                     {
 84                         if (TypeHelper.DicTypeStrs.Contains(type.Name))
 85                             data = SerializeDic((System.Collections.IDictionary)param);
 86                         else if (TypeHelper.ListTypeStrs.Contains(type.Name) || type.IsArray)
 87                             data = SerializeList((System.Collections.IEnumerable)param);
 88                         else
 89                             data = SerializeClass(param, type);
 90                     }
 91                     else if (type.IsClass)
 92                     {
 93                         data = SerializeClass(param, type);
 94                     }
 95 
 96                 }
 97                 if (data != null)
 98                     len = data.Length;
 99             }
100             datas.AddRange(BitConverter.GetBytes(len));
101             if (len > 0)
102             {
103                 datas.AddRange(data);
104             }
105             return datas.Count == 0 ? null : datas.ToArray();
106         }

亚洲必赢手机入口 35亚洲必赢手机入口 36

View Code

View Code

  1   [Serializable]  //必须添加序列化特性
  2 
  3     public class Person
  4 
  5     {
  6 
  7         private string Name;//姓名
  8 
  9         private bool Sex;//性别,是否是男
 10 
 11         public Person(string name, bool sex)
 12 
 13         {
 14 
 15             this.Name = name;
 16 
 17             this.Sex = sex;
 18 
 19         }
 20 
 21         public override string ToString()
 22 
 23         {
 24 
 25             return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");
 26 
 27         }
 28 
 29     }
 30 
 31     [Serializable]  //必须添加序列化特性
 32 
 33     public class Programmer : Person
 34 
 35     {
 36 
 37         private string Language;//编程语言
 38 
 39         public Programmer(string name, bool sex, string language) : base(name, sex)
 40 
 41         {
 42 
 43             this.Language = language;
 44 
 45         }
 46 
 47         public override string ToString()
 48 
 49         {
 50 
 51             return base.ToString() + "\t编程语言:" + this.Language;
 52 
 53         }
 54 
 55     }
 56 
 57     class Program
 58 
 59     {
 60 
 61         static void Main(string[] args)
 62 
 63         {
 64 
 65             //创建Programmer列表,并添加对象
 66 
 67             List<Programmer> list = new List<Programmer>();
 68 
 69             list.Add(new Programmer("李志伟", true, "C#"));
 70 
 71             list.Add(new Programmer("Coder2", false, "C++"));
 72 
 73             list.Add(new Programmer("Coder3", true, "Java"));
 74 
 75             //使用二进制序列化对象
 76 
 77             string fileName = @"D:\users\lizw\桌面\Programmers.dat";//文件名称与路径
 78 
 79             Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
 80 
 81             BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器
 82 
 83             binFormat.Serialize(fStream, list);
 84 
 85             //使用二进制反序列化对象
 86 
 87             list.Clear();//清空列表
 88 
 89             fStream.Position = 0;//重置流位置
 90 
 91             list = (List<Programmer>)binFormat.Deserialize(fStream);//反序列化对象
 92 
 93             foreach (Programmer p in list)
 94 
 95             {
 96 
 97                 Console.WriteLine(p);
 98 
 99             }
100 
101             Console.Read();
102 
103         }
104 
105     }

在进行②进制反种类化(还原对象时),要求将种类化程序聚焦的.exe和.pdb多个文本拷贝进来,并加上对先后集的引用,二进制反系列化很轻易,代码如下:

        反系列化实现如下:

View Code

亚洲必赢手机入口 37亚洲必赢手机入口 38

亚洲必赢手机入口 39亚洲必赢手机入口 40

(2)总结

 1 BinaryFormatter bf = new BinaryFormatter();
 2             string strPath = ConfigurationManager.AppSettings["FilePath"];
 3             StringBuilder sb = new StringBuilder();
 4 
 5             using (FileStream fsRead=new FileStream(strPath,FileMode.Open,FileAccess.Read))
 6             {
 7                 Person p1 = bf.Deserialize(fsRead) as Person;
 8                 if (p1!=null)
 9                 {
10                     Car c1 = p1.MyCar;
11                     if (c1!=null)
12                     {
13                         //登记了车的信息
14                         sb.AppendFormat("姓名:{0};\r\n年龄:{1}岁;\r\n性别:{2};\r\n联系电话:{3};\r\n电子邮箱:{4};\r\n联系地址:{5};\r\n车型:{6};\r\n车牌号:{7}。", p1.SName, p1.IAge, p1.SSex, p1.SPhone, p1.SEmail, p1.SAddress, c1.SCarType, c1.SCarNum);
15                     }
16                     else
17                     {
18                         sb.AppendFormat("姓名:{0};\r\n年龄:{1}岁;\r\n性别:{2};\r\n联系电话:{3};\r\n电子邮箱:{4};\r\n联系地址:{5}。", p1.SName, p1.IAge, p1.SSex, p1.SPhone, p1.SEmail, p1.SAddress);
19                     }
20                 }
21             }
22             lbResult.Text = sb.ToString();
  1         public static object Deserialize(Type type, byte[] datas, ref int offset)
  2         {
  3             dynamic obj = null;
  4 
  5             var len = 0;
  6 
  7             byte[] data = null;
  8 
  9             len = BitConverter.ToInt32(datas, offset);
 10             offset += 4;
 11             if (len > 0)
 12             {
 13                 data = new byte[len];
 14                 Buffer.BlockCopy(datas, offset, data, 0, len);
 15                 offset += len;
 16 
 17                 if (type == typeof(string))
 18                 {
 19                     obj = Encoding.UTF8.GetString(data);
 20                 }
 21                 else if (type == typeof(byte))
 22                 {
 23                     obj = (data);
 24                 }
 25                 else if (type == typeof(bool))
 26                 {
 27                     obj = (BitConverter.ToBoolean(data, 0));
 28                 }
 29                 else if (type == typeof(short))
 30                 {
 31                     obj = (BitConverter.ToInt16(data, 0));
 32                 }
 33                 else if (type == typeof(int))
 34                 {
 35                     obj = (BitConverter.ToInt32(data, 0));
 36                 }
 37                 else if (type == typeof(long))
 38                 {
 39                     obj = (BitConverter.ToInt64(data, 0));
 40                 }
 41                 else if (type == typeof(float))
 42                 {
 43                     obj = (BitConverter.ToSingle(data, 0));
 44                 }
 45                 else if (type == typeof(double))
 46                 {
 47                     obj = (BitConverter.ToDouble(data, 0));
 48                 }
 49                 else if (type == typeof(decimal))
 50                 {
 51                     obj = (BitConverter.ToDouble(data, 0));
 52                 }
 53                 else if (type == typeof(DateTime))
 54                 {
 55                     var dstr = Encoding.UTF8.GetString(data);
 56                     var ticks = long.Parse(dstr.Substring(2));
 57                     obj = (new DateTime(ticks));
 58                 }
 59                 else if (type.BaseType == typeof(Enum))
 60                 {
 61                     var numType = Enum.GetUnderlyingType(type);
 62 
 63                     if (numType == typeof(byte))
 64                     {
 65                         obj = Enum.ToObject(type, data[0]);
 66                     }
 67                     else if (numType == typeof(short))
 68                     {
 69                         obj = Enum.ToObject(type, BitConverter.ToInt16(data, 0));
 70                     }
 71                     else if (numType == typeof(int))
 72                     {
 73                         obj = Enum.ToObject(type, BitConverter.ToInt32(data, 0));
 74                     }
 75                     else
 76                     {
 77                         obj = Enum.ToObject(type, BitConverter.ToInt64(data, 0));
 78                     }
 79                 }
 80                 else if (type == typeof(byte[]))
 81                 {
 82                     obj = (byte[])data;
 83                 }
 84                 else if (type.IsGenericType)
 85                 {
 86                     if (TypeHelper.ListTypeStrs.Contains(type.Name))
 87                     {
 88                         obj = DeserializeList(type, data);
 89                     }
 90                     else if (TypeHelper.DicTypeStrs.Contains(type.Name))
 91                     {
 92                         obj = DeserializeDic(type, data);
 93                     }
 94                     else
 95                     {
 96                         obj = DeserializeClass(type, data);
 97                     }
 98                 }
 99                 else if (type.IsClass)
100                 {
101                     obj = DeserializeClass(type, data);
102                 }
103                 else if (type.IsArray)
104                 {
105                     obj = DeserializeArray(type, data);
106                 }
107                 else
108                 {
109                     throw new RPCPamarsException("ParamsSerializeUtil.Deserialize 未定义的类型:" + type.ToString());
110                 }
111 
112             }
113             return obj;
114         }

选取贰进制连串化,必须为每三个要类别化的的类和其关联的类增进[Serializable]性格,对类中不须求类别化的分子能够使用[NonSerialized]特性。

View Code

View Code

二进制连串化对象时,能种类化类的具有成员(包含个人的),且不须求类有无参数的构造方法。

再来讲说Json种类化,先上代码:

     
  其余详细的代码能够查看ParamsSerializeUtil.cs

运用二进制格式体系化时,它不只是将对象的字段数据开始展览持久化,也持久化各样品种的完全限定名称和概念程序集的欧洲经济共同体名称(包涵包称、版本、公钥标识、区域性),那一个数据驱动在进展二进制格式反体系化时亦会开始展览项目检查。所以反类别化时的运行情形要与种类化时的运营条件要平等,否者恐怕会非常的小概反体系化成功。

亚洲必赢手机入口 41亚洲必赢手机入口 42

     
  效率为主落到实处了,上边相比一下10000次的实业种类化与反类别化测试结果:

三.使用SOAP方式连串化和反类别化

 1 Console.WriteLine("请输入您的姓名:");
 2             string sName = Console.ReadLine();
 3             if (!string.IsNullOrEmpty(sName))
 4             {
 5                 Console.WriteLine("{0},请输入你的年龄:",sName);
 6                 int iAge = int.Parse(Console.ReadLine());
 7                 Console.WriteLine("{0},请输入你的性别:",sName);
 8                 string sSex = Console.ReadLine();
 9                 Console.WriteLine("{0},请输入你的E-Mail地址:",sName);
10                 string sEmail = Console.ReadLine();
11                 Console.WriteLine("{0},请输入你的联系电话:",sName);
12                 string sPhone = Console.ReadLine();
13                 Console.WriteLine("{0},请输入你的通信地址:",sName);
14                 string sAddress = Console.ReadLine();
15 
16                 Person p = new Person(sName, iAge, sSex, sEmail, sPhone, sAddress);
17                 JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
18                 //执行Json序列化
19                 File.WriteAllText("demo.txt", jsSerializer.Serialize(p));
20                 Console.WriteLine("Json序列化完毕");

        实体代码:

(一)SOAP类别化与反序列化的程序示例

View Code

 1             var groupInfo = new GroupInfo()
 2             {
 3                 GroupID = 1,
 4                 IsTemporary = false,
 5                 Name = "yswenli group",
 6                 Created = DateTimeHelper.Now,
 7                 Creator = new UserInfo()
 8                 {
 9 
10                     ID = 1,
11                     Birthday = DateTimeHelper.Now.AddYears(-100),
12                     UserName = "yswenli"
13                 },
14                 Users = new System.Collections.Generic.List<UserInfo>()
15                 {
16                     new UserInfo()
17                     {
18 
19                         ID = 1,
20                         Birthday = DateTimeHelper.Now.AddYears(-100),
21                         UserName = "yswenli"
22                     }
23                 }
24             };

亚洲必赢手机入口 43亚洲必赢手机入口 44

Json类别化好的数量是1对大括号括起来的,各类数据由属性名和值中间加个“:”组成。

        测试代码:

 1 [Serializable]  //必须添加序列化特性
 2 
 3     public class Person
 4 
 5     {
 6 
 7         private string Name;//姓名
 8 
 9         private bool Sex;//性别,是否是男
10 
11         public Person(string name, bool sex)
12 
13         {
14 
15             this.Name = name;
16 
17             this.Sex = sex;
18 
19         }
20 
21         public override string ToString()
22 
23         {
24 
25             return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");
26 
27         }
28 
29     }
30 
31     [Serializable]  //必须添加序列化特性
32 
33     public class Programmer : Person
34 
35     {
36 
37         private string Language;//编程语言
38 
39         public Programmer(string name, bool sex, string language) : base(name, sex)
40 
41         {
42 
43             this.Language = language;
44 
45         }
46 
47         public override string ToString()
48 
49         {
50 
51             return base.ToString() + "\t编程语言:" + this.Language;
52 
53         }
54 
55     }
56 
57     class Program
58 
59     {
60 
61         static void Main(string[] args)
62 
63         {
64 
65             //实例化对象
66 
67             Programmer p = new Programmer("李志伟", true, "C、C#、C++、Java");
68 
69             //使用SOAP序列化对象
70 
71             string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径
72 
73             Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
74 
75             SoapFormatter soapFormat = new SoapFormatter();//创建SOAP序列化器
76 
77             soapFormat.Serialize(fStream, p);//SOAP不能序列化泛型对象
78 
79             //使用SOAP反序列化对象
80 
81             fStream.Position = 0;//重置流位置
82 
83             p = null;
84 
85             p = (Programmer)soapFormat.Deserialize(fStream);
86 
87             Console.WriteLine(p);
88 
89             Console.Read();
90 
91         }
92 
93     }

Json反种类化同样不会细小略,同理,也需求将体系化程序集中的.exe和.pdb五个文本拷贝进来,并累加对先后集的引用,代码如下:

亚洲必赢手机入口 45亚洲必赢手机入口 46

View Code

Json反系列化

 1         public static byte[] SerializeBinary(object request)
 2         {
 3 
 4             System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer =
 5 
 6             new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
 7 
 8             using (System.IO.MemoryStream memStream = new System.IO.MemoryStream())
 9             {
10                 serializer.Serialize(memStream, request);
11 
12                 return memStream.ToArray();
13             }
14         }
15 
16 
17         public static object DeSerializeBinary(byte[] data)
18         {
19             using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(data))
20             {
21                 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter deserializer =
22 
23                 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
24 
25                 return deserializer.Deserialize(memStream);
26             }
27         }
28 
29         static void SerializeTest()
30         {
31             var groupInfo = new GroupInfo()
32             {
33                 GroupID = 1,
34                 IsTemporary = false,
35                 Name = "yswenli group",
36                 Created = DateTimeHelper.Now,
37                 Creator = new UserInfo()
38                 {
39 
40                     ID = 1,
41                     Birthday = DateTimeHelper.Now.AddYears(-100),
42                     UserName = "yswenli"
43                 },
44                 Users = new System.Collections.Generic.List<UserInfo>()
45                 {
46                     new UserInfo()
47                     {
48 
49                         ID = 1,
50                         Birthday = DateTimeHelper.Now.AddYears(-100),
51                         UserName = "yswenli"
52                     }
53                 }
54             };
55 
56             var count = 100000;
57             var len1 = 0;
58             var len2 = 0;
59 
60             Stopwatch sw = new Stopwatch();
61             sw.Start();
62 
63             List<byte[]> list = new List<byte[]>();
64             for (int i = 0; i < count; i++)
65             {
66                 var bytes = SerializeBinary(groupInfo);
67                 len1 = bytes.Length;
68                 list.Add(bytes);
69             }
70             ConsoleHelper.WriteLine($"BinaryFormatter实体序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
71 
72             sw.Restart();
73             for (int i = 0; i < count; i++)
74             {
75                 var obj = DeSerializeBinary(list[i]);
76             }
77             ConsoleHelper.WriteLine($"BinaryFormatter实体反序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
78             ConsoleHelper.WriteLine($"BinaryFormatter序列化生成bytes大小:{len1 * count * 1.0 / 1024 / 1024} Mb");
79             list.Clear();
80             sw.Restart();
81 
82             for (int i = 0; i < count; i++)
83             {
84                 var bytes = RPC.Serialize.ParamsSerializeUtil.Serialize(groupInfo);
85                 len2 = bytes.Length;
86                 list.Add(bytes);
87             }
88             ConsoleHelper.WriteLine($"ParamsSerializeUtil实体序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
89             sw.Restart();
90             for (int i = 0; i < count; i++)
91             {
92                 int os = 0;
93 
94                 var obj = RPC.Serialize.ParamsSerializeUtil.Deserialize(groupInfo.GetType(), list[i], ref os);
95             }
96             ConsoleHelper.WriteLine($"ParamsSerializeUtil实体反序列化平均:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
97             ConsoleHelper.WriteLine($"ParamsSerializeUtil序列化生成bytes大小:{len2 * count * 1.0 / 1024 / 1024} Mb");
98             sw.Stop();
99         }

(2)总结

亚洲必赢手机入口 47亚洲必赢手机入口 48

View Code

SOAP类别化与贰进制连串化的界别是:SOAP种类化无法系列化泛型类型。与二进制系列化一样在系列化时不须要向体系化器内定种类化对象的花色。而XML种类化供给向XML体系化器钦定连串化对象的等级次序。

 1 string sPath = ConfigurationManager.AppSettings["FilePath"];
 2             string sContent = File.ReadAllText(sPath, Encoding.UTF8);
 3 
 4             JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
 5             //这里使用泛型方法可以避免类型转换,方便使用!
 6             Person p1 = jsSerializer.Deserialize<Person>(sContent);
 7             Console.WriteLine("姓名:" + p1.SName);
 8             Console.WriteLine("性别:"+p1.SSex);
 9             Console.WriteLine("年龄:"+p1.IAge.ToString());
10             Console.WriteLine("联系电话:"+p1.SPhone);
11             Console.WriteLine("E-mail:"+p1.SEmail);
12             Console.WriteLine("联系地址:"+p1.SAddress);
13             Console.ReadKey();

        运营结果:

4.运用XML格局类别化和反系列化

View Code

亚洲必赢手机入口 49 

(一)XML体系化与反种类化的程序示例

末段说一下今日自家在做Json类别化时,碰着的三个主题材料:在写出类名JavaScript塞里alizer后怎么都无法引用(类名也不会变丁香紫),在英特网查了下,终于找到方法(小编用的是Visual
Studio 20拾,2011也不行):

亚洲必赢手机入口 50亚洲必赢手机入口 51

率先在品种上右击“属性”,假使目的框架是:.net framework 4 Client
profile的,自然引用不了,要改成正规版,即选不带后缀(不带Client
profile的),更换后项目中自然多了二个app.config项目布局文件,再引用System.web.Extensions那一个顺序集。难题就能够缓慢解决。

  1 public class Person
  2 
  3     {
  4 
  5         public string Name;//姓名
  6 
  7         public bool Sex;//性别,是否是男
  8 
  9         public Person() { }//必须提供无参构造器,否则XmlSerializer将出错
 10 
 11         public Person(string name, bool sex)
 12 
 13         {
 14 
 15             this.Name = name;
 16 
 17             this.Sex = sex;
 18 
 19         }
 20 
 21         public override string ToString()
 22 
 23         {
 24 
 25             return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");
 26 
 27         }
 28 
 29     }
 30 
 31     public class Programmer : Person
 32 
 33     {
 34 
 35         public string Language;//编程语言
 36 
 37         public Programmer() { }//必须提供无参构造器,否则XmlSerializer将出错
 38 
 39         public Programmer(string name, bool sex, string language) : base(name, sex)
 40 
 41         {
 42 
 43             this.Language = language;
 44 
 45         }
 46 
 47         public override string ToString()
 48 
 49         {
 50 
 51             return base.ToString() + "\t编程语言:" + this.Language;
 52 
 53         }
 54 
 55     }
 56 
 57     class Program
 58 
 59     {
 60 
 61         static void Main(string[] args)
 62 
 63         {
 64 
 65             //创建Programmer列表,并添加对象
 66 
 67             List<Programmer> list = new List<Programmer>();
 68 
 69             list.Add(new Programmer("李志伟", true, "C#"));
 70 
 71             list.Add(new Programmer("Coder2", false, "C++"));
 72 
 73             list.Add(new Programmer("Coder3", true, "Java"));
 74 
 75             //使用XML序列化对象
 76 
 77             string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径
 78 
 79             Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
 80 
 81             XmlSerializer xmlFormat = new XmlSerializer(
 82 
 83 typeof(List<Programmer>),
 84 
 85 new Type[] { typeof(Programmer),typeof(Person) }
 86 
 87 );//创建XML序列化器,需要指定对象的类型
 88 
 89             xmlFormat.Serialize(fStream, list);
 90 
 91             //使用XML反序列化对象
 92 
 93             fStream.Position = 0;//重置流位置
 94 
 95             list.Clear();
 96 
 97             list = (List<Programmer>)xmlFormat.Deserialize(fStream);
 98 
 99             foreach (Programmer p in list)
100 
101             {
102 
103                 Console.WriteLine(p);
104 
105             }
106 
107             Console.Read();
108 
109         }
110 
111     }

 

View Code

(2)总结

使用XML种类化或反种类化时,供给对XML类别化器内定需求种类化对象的连串和其关联的种类。

XML体系化只好体系化对象的公有属性,并且须求对象有一个无参的构造方法,否者无法反种类化。

[Serializable]和[NonSerialized]特点对XML系列化无效!所以选择XML种类化时不需求对目标扩张[Serializable]特性。

五.XML连串化对象详解

(1)说明

本节最首要介绍:使用个性决定目标类别化成XML文件的格式。

(2)使用XmlElement(默认值)

类声明:

亚洲必赢手机入口 52亚洲必赢手机入口 53

public class Person

    {

        [XmlElement]

        public string Name;//使用[XmlElement]特性

        public bool Sex;//默认使用了[XmlElement]特性

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

View Code

系列化生成的XML文件:

<Personxmlns:xsi="..."xmlns:xsd="...">
  <Name>李志伟</Name>
  <Sex>true</Sex>
</Person>

(3)使用XmlAttribute

类声明:

public class Person
{
    [XmlElement]
    public string Name;
    [XmlAttribute]
    public bool Sex;
    public Person() { }//必须提供无参构造器,否则XmlSerializer将出错
}

系列化生成的XML文件:

<Personxmlns:xsi="..."xmlns:xsd="..."Sex="true">
  <Name>李志伟</Name>
</Person>

(4)使用XmlText

类声明:

public class Person
{
   [XmlText]
    public string Name;
    [XmlAttribute]
    public bool Sex;
    public Person() { }//必须提供无参构造器,否则XmlSerializer将出错
}

系列化生成的XML文件:

<Personxmlns:xsi="..."xmlns:xsd="..."Sex="true">李志伟</Person>

(5)使用XmlType和XmlAttribute(重命名节点名称)

类声明:  

 [XmlType("个人信息")]
    public class Person
    {
        [XmlAttribute("姓名")]
        public string Name;
        [XmlAttribute("性别")]
        public bool Sex;
        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错
    }

类别化生成的XML文件:

<个人信息xmlns:xsi="..."xmlns:xsd="..."姓名="李志伟"性别="true" />

(六)列表和数组的种类化

类声明:

亚洲必赢手机入口 54亚洲必赢手机入口 55

[XmlType("个人信息")]

    public class Person

    {

        [XmlAttribute("姓名")]

        public string Name;

        [XmlAttribute("性别")]

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    class Program

    {

        static void Main(string[] args)

        {

            Person p = new Person();

            p.Name = "李志伟";

            p.Sex = true;

            Person[] ps = new Person[3];

            ps[0] = p;

            ps[1] = p;

            ps[2] = p;

            //使用XML序列化对象

            string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

            Stream fStream = new FileStream(fileName, FileMode.Create);

            XmlSerializer xmlFormat = new XmlSerializer(typeof(Person[]));

            xmlFormat.Serialize(fStream, ps);//序列化对象

            fStream.Dispose();//关闭文件

            Console.WriteLine("OK!");

            Console.Read();

        }

    }

View Code

类别化生成的XML文件:

<ArrayOf个人信息xmlns:xsi="..."xmlns:xsd="...">
  <个人信息姓名="李志伟"性别="true" />
  <个人信息姓名="李志伟"性别="true" />
  <个人信息姓名="李志伟"性别="true" />
</ArrayOf个人信息>

注意:开采此时的XML文件的根节点名称变了。此时要重命名根节点应使用如下方式:

亚洲必赢手机入口 56亚洲必赢手机入口 57

 [XmlType("个人信息")]

    public class Person

    {

        [XmlAttribute("姓名")]

        public string Name;

        [XmlAttribute("性别")]

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    [XmlType("人员信息")]

    public class PersonArray : List<Person> { }

    class Program

    {

        static void Main(string[] args)

        {

            Person p = new Person();

            p.Name = "李志伟";

            p.Sex = true;

            PersonArray ps = new PersonArray();

            ps.Add(p);

            ps.Add(p);

            ps.Add(p);

            //使用XML序列化对象

            string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

            Stream fStream = new FileStream(fileName, FileMode.Create);

            XmlSerializer xmlFormat = new XmlSerializer(typeof(PersonArray));

            xmlFormat.Serialize(fStream, ps);//序列化对象

            fStream.Dispose();//关闭文件

            Console.WriteLine("OK!");

            Console.Read();

        }

    }

View Code

体系化生成的XML文件:

<人员信息xmlns:xsi="..."xmlns:xsd="...">
  <个人信息姓名="李志伟"性别="true" />
  <个人信息姓名="李志伟"性别="true" />
  <个人信息姓名="李志伟"性别="true" />
</人员信息>

(7)列表和数组的做为数据成员的种类化

类声明:

亚洲必赢手机入口 58亚洲必赢手机入口 59

 [XmlType("信息")]

    public class Person

    {

        [XmlAttribute("姓名")]

        public string Name;

        [XmlAttribute("性别")]

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    public class PersonArray

    {

        public List<Person> Array=new List<Person>();

        public Person Person = new Person();

    }

    class Program

    {

        static void Main(string[] args)

        {

            PersonArray ps = new PersonArray();

            ps.Person = new Person();

            ps.Person.Name = "李志伟";

            ps.Person.Sex = true;

            ps.Array.Add(ps.Person);

            ps.Array.Add(ps.Person);

            ps.Array.Add(ps.Person);

            //使用XML序列化对象

            string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

            Stream fStream = new FileStream(fileName, FileMode.Create);

            XmlSerializer xmlFormat = new XmlSerializer(typeof(PersonArray));

            xmlFormat.Serialize(fStream, ps);//序列化对象

            fStream.Dispose();//关闭文件

            Console.WriteLine("OK!");

            Console.Read();

        }

    }

View Code

种类化生成的XML文件:

<PersonArrayxmlns:xsi="..."xmlns:xsd="...">
  <Array>
    <个人信息姓名="李志伟"性别="true" />
    <个人信息姓名="李志伟"性别="true" />
    <个人信息姓名="李志伟"性别="true" />
  </Array>
  <Person姓名="李志伟"性别="true" />
</PersonArray>

注意:即便那里供给为Array和Person的节点重命名,代码如下:

亚洲必赢手机入口 60亚洲必赢手机入口 61

 [XmlType("信息")]

    public class Person

    {

        [XmlAttribute("姓名")]

        public string Name;

        [XmlAttribute("性别")]

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    public class PersonArray

    {

        [XmlArrayItem("个人信息")]

        [XmlArray("人员信息")]

        public List<Person> Array=new List<Person>();

        public Person Person = new Person();

    }

View Code

种类化生成的XML文件:

<PersonArrayxmlns:xsi="..."xmlns:xsd="...">
  <人员信息>
    <个人信息姓名="李志伟"性别="true" />
    <个人信息姓名="李志伟"性别="true" />
    <个人信息姓名="李志伟"性别="true" />
  </人员信息>
  <Person姓名="李志伟"性别="true" />
</PersonArray>

注意:把“人士音信”节点去掉吧(直接出现“个人新闻”节点)

亚洲必赢手机入口 62亚洲必赢手机入口 63

  [XmlType("信息")]

    public class Person

    {

        [XmlAttribute("姓名")]

        public string Name;

        [XmlAttribute("性别")]

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    public class PersonArray

    {

        [XmlElement("个人信息")]

        public List<Person> Array=new List<Person>();

        public Person Person = new Person();

    }

序列化生成的XML文件:

<PersonArrayxmlns:xsi="..."xmlns:xsd="...">

  <个人信息姓名="李志伟"性别="true" />

  <个人信息姓名="李志伟"性别="true" />

  <个人信息姓名="李志伟"性别="true" />

  <Person姓名="李志伟"性别="true" />

</PersonArray>

(8)类型继承与反序列化

类声明:

    public class Base { }

    [XmlType("信息A")]

    public class PersonA : Base

    {

        [XmlAttribute("姓名")]

        public string Name;

        [XmlAttribute("性别")]

        public bool Sex;

        public PersonA() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    [XmlType("信息B")]

    public class PersonB : Base

    {

        [XmlElement("姓名")]

        public string Name;

        [XmlElement("年龄")]

        public int Age;

        public PersonB() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

    [XmlType("人员信息")]

    public class PersonArray

    {

        [XmlArrayItem(typeof(PersonA)), XmlArrayItem(typeof(PersonB))]

        public List<Base> ListPerson=new List<Base>();

    }

    class Program

    {

        static void Main(string[] args)

        {

            PersonA pa = new PersonA();

            pa.Name = "李志伟A";

            pa.Sex = true;

            PersonB pb = new PersonB();

            pb.Name = "李志伟B";

            pb.Age = 21;

            PersonArray ps = new PersonArray();

            ps.ListPerson.Add(pa);

            ps.ListPerson.Add(pa);

            ps.ListPerson.Add(pb);

            ps.ListPerson.Add(pb);

            //使用XML序列化对象

            string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

            Stream fStream = new FileStream(fileName, FileMode.Create);

            XmlSerializer xmlFormat = new XmlSerializer(typeof(PersonArray));

            xmlFormat.Serialize(fStream, ps);//序列化对象

            fStream.Dispose();//关闭文件

            Console.WriteLine("OK!");

            Console.Read();

        }

    }

View Code

种类化生成的XML文件:

<人员信息xmlns:xsi="..."xmlns:xsd="...">
  <ListPerson>
    <信息A姓名="李志伟A"性别="true" />
    <信息A姓名="李志伟A"性别="true" />
    <信息B>
      <姓名>李志伟B</姓名>
      <年龄>21</年龄>
    </信息B>
    <信息B>
      <姓名>李志伟B</姓名>
      <年龄>21</年龄>
    </信息B>
  </ListPerson>
</人员信息>

意:还要为列表成员钦命多少个[XmlArrayItem(typeof(XXX))]可落成四种派生类型混在一块输出。

(九)排除不必要种类化的成员

类声明:

  public class Person
    {
        public string Name;
        [XmlIgnore]// 这个属性将不会参与序列化
        public bool Sex;
        public Person() { }
    }

种类化生成的XML文件:

<Personxmlns:xsi="..."xmlns:xsd="...">
  <Name>李志伟</Name>
</Person>

(拾)强制钦命成员的种类化顺序

类声明:

   

亚洲必赢手机入口 64亚洲必赢手机入口 65

 public class Person

    {

        [XmlElement(Order = 2)]

        public string Name;

        [XmlElement(Order = 1)]

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

    }

View Code

连串化生成的XML文件:

<Personxmlns:xsi="..."xmlns:xsd="...">
  <Sex>true</Sex>
  <Name>李志伟</Name>
</Person>

(1一)自定义种类化行为

类声明:

亚洲必赢手机入口 66亚洲必赢手机入口 67

 public class Person : IXmlSerializable

    {

        public string Name;

        public bool Sex;

        public Person() { }//必须提供无参构造器,否则XmlSerializer将出错

        public System.Xml.Schema.XmlSchema GetSchema()

        {

            return null;

        }

        public void ReadXml(System.Xml.XmlReader reader)

        {

            Name = reader.GetAttribute("姓名");

            Sex = reader.GetAttribute("性别").Equals("男") ? true : false;

        }

        public void WriteXml(System.Xml.XmlWriter writer)

        {

            writer.WriteAttributeString("姓名", Name);

            writer.WriteAttributeString("性别", Sex ? "男" : "女");

        }

    }

View Code

种类化生成的XML文件:

<Person姓名="李志伟"性别="男" />

(12)种类化设置XML命名空间

类声明:

[XmlRoot(Namespace = "http://msdn.microsoft.com/vsdh.xsd")]
    public class Person
    {
        public string Name;
        public bool Sex;
        public Person() { }
    }

连串化生成的XML文件:

<Personxmlns:xsi="..."xmlns:xsd="..."xmlns="http://msdn.microsoft.com/vsdh.xsd">
  <Name>李志伟A</Name>
  <Sex>true</Sex>
</Person>

(一叁)XML的施用建议

在服务端,C#代码中:

一. 提议不要选取低端别的XML
API来利用XML,除非您是在图谋框架可能通用类库。

二. 提出使用系列化、反类别化的形式来扭转照旧读取XML

叁. 当需求牵记使用XML时,先不要想着XML结构,先应该定义好数据类型。

四. 列表节点不要选用[XmlElement],它会让全部子节点【晋级】,显得结构混乱。

5. 借使指望体系化的XML长度小一些,能够利用[XmlAttribute],也许钦赐一个更加短小的外号。

陆. 不要在一个列表中输出不相同的数据类型,那样的XML结构的可读性倒霉。

7. 尽恐怕选取UTF-8编码,不要选取GB2312编码。

在客户端,JavaScript代码中,我不提议选取XML,而是建议选择JSON来取代XML,因为:

一.
XML文书的长短比JSON要长,会占用更加多的互联网传输时间(究竟数据保存在服务端,所以传输是免不了的)。

2. 在JavaScritp中应用XML比较费心(还有浏览器的包容难点),反而各类浏览器对JSON有分外好的帮衬。

(14)反连串化的施用总计

若是XML是由项目系列化得到那的,那么反体系化的调用代码是很轻巧的,反之,假若要直面三个从没有过项目的XML,就供给我们先规划一个(或然局地)类型出来,那是一个逆向推导的历程,请参考以下步骤:

壹. 第二要分析任何XML结构,定义与之同盟的类型,

二. 壹旦XML结构有嵌套档期的顺序,则须求定义三个等级次序与之同盟,

三. 定义具体品种(三个层级下的XML结构)时,请参见以下表格。

XML形式

处理方法

补充说明

XmlElement

定义一个属性

属性名与节点名字匹配

XmlAttribute

[XmlAttribute] 加到属性上

 

InnerText

[InnerText] 加到属性上

一个类型只能使用一次

 

 

节点重命名

根节点:[XmlType("testClass")] 
元素节点:[XmlElement("name")] 
属性节点:[XmlAttribute("id")] 
列表子元素节点:[XmlArrayItem("Detail")] 
列表元素自身:[XmlArray("Items")]

 

六.自定义种类化(仅适用于贰进制与SOAP)

(1)自定义体系化的兑现格局

能够透过在对象上贯彻 ISerializable 接口来自定义种类化进度。那壹效用在反类别化后成员变量的值失效时尤其有用,可是急需为变量提供值以重建对象的总体气象。要贯彻ISerializable,需求完毕 GetObjectData()方法以及二个非凡的构造函数,在反体系化对象时要用到此构造函数。

(二)示例程序   

亚洲必赢手机入口 68亚洲必赢手机入口 69

[Serializable]

    public class Person : ISerializable

    {

        public string Name;

        public bool Sex;

        public Person() { }

        //必须的够着方法,反序列化时调用

        protected Person(SerializationInfo info, StreamingContext context)

        {

            Name = info.GetString("姓名");

            Sex = info.GetBoolean("性别");

        }

        //序列化时调用

        public void GetObjectData(SerializationInfo info, StreamingContext context)

        {

            info.AddValue("姓名", Name + "(自定义序列化)");

            info.AddValue("性别", Sex);

        }

        public override string ToString()

        {

            return "姓名:" + this.Name + "\t性别:" + (this.Sex ? "男" : "女");

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            Person p = new Person();

            p.Name = "李志伟A";

            p.Sex = true;

            //使用二进制序列化对象

            string fileName = @"D:\users\lizw\桌面\Programmers.xml";//文件名称与路径

            Stream fStream = new FileStream(fileName, FileMode.Create);

            BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器

            binFormat.Serialize(fStream, p);//序列化对象

            //使用二进制反序列化对象

            fStream.Position = 0;//重置流位置

            p = (Person)binFormat.Deserialize(fStream);//反序列化对象

            Console.WriteLine(p);

            fStream.Dispose();//关闭文件

            Console.WriteLine("OK!");

            Console.Read();

        }

    }

View Code

注意:在连串化进度中调用 GetObjectData()时,须要填写方法调用中提供的塞里alizationInfo对象。只需按名称/值对的样式丰裕将要类别化的变量。其名称能够是别的公文。只要已类别化的数据足以在反连串化进程中回复对象,便能够自由接纳加多至SerializationInfo 的分子变量。如若基对象完成了 ISerializable,则派生类应调用其基对象的 GetObjectData()方法。一样,在反类别化时也会调用含有(SerializationInfo info, StreamingContextcontext)参数的卓殊的够着办法!否者将不可能反体系化!!!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图