种类化和反连串,中的贰进制类别化和Json体系化

       
2进制类别化能够方便飞速的将目标开始展览持久化或然互联网传输,并且体积小、质量高,应用面乃至还要高于json的系列化;先导在此以前,先来看看dotcore/dotne自带的2进制种类化:C#中目的系列化和反连串化一般是通过BinaryFormatter类来兑现的2进制连串化、反类别化的。

3、流和系列化

一.对象连串化的介绍

体系化正是把1个目标产生流的款型,方便传输和回复。四弟不才,计算下对贰进制体系化和Json体系化的选择:

        BinaryFormatter序列化:

种类化和反连串,中的贰进制类别化和Json体系化。三.一 流概念及.NET中常见流

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

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

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

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

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

 

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

澳门葡京备用网址 1

  从上海体育场面中得以窥见,Stream类型承继自马尔斯halByRefObject类型,那保障了流类型能够超越应用程序域进行互动

  下边包车型地铁代码中呈现了哪些在.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

  在实际开辟中时时会遇上须要传递一个非常的大的文件,或然事先不恐怕获悉文件大小,因此也就不可能成立二个尺码正好适合的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中,通过轮回的壹再读写和写入实现整个复制操作。

(1).NET协理对象种类化的三种艺术

壹.第3,贰进制体系化(BinaryFormatter)要求要类别化的类必须是可连串化的(即在类定义的眼下加Serializable关键字),而且它的父类类型也非得是可系列化的,经过查阅开掘,Dotnet中过多品类和结构都有其一标识;而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);

3.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 类压缩大于 4 GB 的公文时将会吸引那多少个

  通过GZipStream的构造方法能够观看,它是贰个超级的Decorator装饰者情势的运用,所谓装饰者方式,正是动态地给多个对象加多一些外加的天职。对于扩张新效用这些上面,装饰者方式比新扩张八个子类更为灵活。就拿地点代码中的GZipStream来说,它扩张的是MemoryStream,为Write方法扩展了削减的功能,从而落成了滑坡的采纳。

澳门葡京备用网址 10

扩展:过多材质注脚.NET提供的GZipStream和DeflateStream类型的压缩算法并不能,也无法调节压缩率,某个第贰方的组件比方SharpZipLib实现了更迅捷的缩减和解压算法,大家得以在nuget中为项目增加该器件。

澳门葡京备用网址 11

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

贰.一旦类中一些品质不愿意被2进制种类化,加NonSerialized关键字就可以,而要2进制种类化的性质的品类必须是可系列化的数据类型;

        BinaryFormatter反种类化:

三.三 Serializable性情有如何功能?

  通过下边包车型大巴流类型能够1本万利地操作种种字节流,然则怎么把现有的实例对象转变为便宜传输的字节流,就需求利用体系化才具。对象实例的系列化,是指将实例对象转变为可便宜存款和储蓄、传输和互相的流。在.NET中,通过Serializable特色提供了种类化对象实例的体制,当2个门类被发明为Serializable后,它就能被诸如BinaryFormatter等落到实处了IFormatter接口的项目实行体系化和反连串化。

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

  可是,在骨子里支出中我们会蒙受对于有个别破例的不指望被体系化的积极分子,那时咱们可认为一些成员增多NonSerialized特征。举例,有如下代码所示的3个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

注意:当一个基类使用了Serializable天性后,并不表示其具备子类都能被类别化。事实上,大家不能够不为每一种子类都加多Serializable个性才能确认保证其能被准确地连串化。

SOAP序列化:对象系列化之后的结果符合SOAP协议,也正是足以经过SOAP 协议传输,通过System.Runtime.Serialization.Formatters.Soap命名空间下的SoapFormatter类来完毕的。

三.2进制系列化只会对类中的字段(属性)系列化,故系列化时不提出选拔机关属性(每回更改的字段都只怕区别样,影响反体系化)。

 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提供了哪两种可开始展览类别化操作的档期的顺序?

  大家已经知道了如何把二个体系证明为可体系化的项目,不过万里长征只走了第二步,具体做到连串化和反体系化的操作还必要3个实施那一个操作的花色。为了体系化具体实例到某种专用的格式,.NET中提供了三种对象系列格式化类型:BinaryFormatterSoapFormatterXmlSerializer

  (1)BinaryFormatter

  顾名思义,BinaryFormatter可用于将可连串化的靶子种类化成二进制的字节流,在目前Serializable特性的代码示例中早就显示过,那里不再另行展现。

  (2)SoapFormatter

  SoapFormatter从事于将可类别化的门类系列化成适合SOAP规范的XML文书档案以供役使。在.NET中,要采取SoapFormatter须求先增添对于SoapFormatter的引用:

using System.Runtime.Serialization.Formatters.Soap;

Tips:SOAP是1种位于应用层的网络协议,它依据XML,并且是Web
Service的主导协议。

  (3)XmlSerializer

  XmlSerializer并不仅仅针对那个标志了Serializable性情的项目,更为必要小心的是,Serializable和NonSerialized天性在XmlSerializer类型对象的操作中全然不起效能,替代它的是XmlIgnore属性。Xml塞里alizer可以对尚未标识Serializable本性的品类对象进行系列化,不过它照旧有必然的限量:

  ①
选拔Xml塞里alizer连串化的对象必须出示地有着3个无参数的国有构造方法

  由此,大家须求修改前面代码示例中的Person类,增加三个无参数的公物构造方法:

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

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

  由此,Person类中的私有成员_number便无法被XmlSerializer举办系列化:

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

  (四)综合示范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.Serialization命名空间下。XML系列化无法类别化私有数量。

上边是2进制类别化的代码:

     
  用着多了就意识BinaryFormatter有那三个地方不妥,上边就来数数那一个体系化的“三宗罪”:

三.5 如何自定义连串化和反连串化的历程?

  对于有些类型,系列化和反连串化往往有一些特殊的操作或逻辑检查须要,那时就必要大家能够主动地决定系列化和反类别化的经过。.NET中提供的Serializable性子帮衬我们那些快捷地评释了3个可类别化的类型(由此也就缺失了灵活性),但广大时候是因为职业逻辑的渴求,大家供给积极地操纵体系化和反连串化的经过。由此,.NET提供了ISerializable接口来满意自定义种类化须要。

   上面包车型客车代码显示了自定义体系化和反类别化的门类模板:

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

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

  如上代码所示,GetObjectData和新鲜构造方法都收到几个参数:SerializationInfo
类型参数的功效类似于三个哈希表,通过key/value对来囤积整个对象的始末,而StreamingContext
类型参数则含有了流的近年来情状,大家能够依据此参数来决断是或不是须求连串化和反类别化类型独享。

  如若基类完成了ISerializable接口,则派生类要求针对自个儿的成员贯彻反类别化构造方法,并且重写基类中的GetObjectData方法。

  上面通过1个有血有肉的代码示例,来驾驭哪些在.NET程序中自定义类别化和反连串化的长河:

  一先是大家需求3个急需被种类化和反种类化的体系,该项目有十分大可能率被其它项目承继

澳门葡京备用网址 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

  二接着编写三个继续自MyObject的子类,并累加2个民用的成员变量。必要留意的是:子类必须担任体系化和反类别化自个儿足够的成员变量

澳门葡京备用网址 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

  3末段编写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特性的成员。

(2)二种种类化的分别

一.要体系化的类的定义:

     
  一.类名地点要抬高[Serializable],不加不给体系化;符合规律的用法应该是类别化三个对象,不需的地点加上NonSerialized才合理吧;

2进制格式和SOAP格式可连串化多个类型的持有可类别化字段,不管它是公家字段还是个体字段。XML格式仅能体系化公共字段或具有公共属性的个体字段,未通过质量公开的个体字段将被忽略。

澳门葡京备用网址 29澳门葡京备用网址 30

     
  2.序列化byte[]结果相当大,使用System.Text.Encoding.UTF八.GetString(bytes)查看下,开采里面有一大堆的元数据;比较看看google的protobuf,pb为何在互连网上行使的进一步多,那和她作者体系化完后容量小有着绝大部门的缘故;

动用二进制格式体系化时,它不光是将目的的字段数据实行持久化,也持久化各类类别的完全限定名称和概念程序集的完好名称(包涵包称、版本、公钥标识、区域性),这个多少驱动在进展二进制格式反体系化时亦会实行项目检查。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     }

     
  三.体系化对象急需完全壹致,连类的命名空间都要一律,这一点对于分面式开采的应用来讲也是不可承受的;

(三)使用天性对体系化的调控

View Code

     
  既然BinaryFormatter倒霉用,那就只能入手动和自动行完毕三个消除上述难点的2进制种类化方案;首先排除[Serializable]本条标签,接着主尽管分析对象,并定义对象类别化后的数据结构;那里的主张是按长度加内容的格局来定义,比如:使用int作为长度,来保存多少个int值,体系化完应该是:四,0,0,0,壹,0,0,0这么的壹组bytes,同理能够将int、short、long、float、double、datetime、enum、array、string、class、generic等依据那一个格式举行体系化,那里最首要利用的是BitConverter、反射等来完成种类化与反种类化;

要让二个目的协助.Net种类化服务,用户必须为每1个提到的类增进[Serializable]特征。即便类中稍加成员不相符加入系列化(比方:密码字段),能够在那些域前增多[NonSerialized]特性。

二.2进制类别化代码:

        系列化达成如下:

贰.使用二进制连串化和反类别化

澳门葡京备用网址 31澳门葡京备用网址 32

澳门葡京备用网址 33澳门葡京备用网址 34

(1)二进制系列化与反种类化的先后示例

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         }

选择贰进制体系化,必须为每1个要体系化的的类和其关联的类拉长[Serializable]特色,对类中不须要系列化的积极分子可以运用[NonSerialized]特性。

View Code

View Code

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

再来讲说Json系列化,先上代码:

     
  别的详细的代码能够查阅ParamsSerializeUtil.cs

利用2进制格式类别化时,它不仅仅是将目标的字段数据举办持久化,也持久化各个类其他完全限定名称和概念程序集的全体名称(包蕴包称、版本、公钥标记、区域性),这个数量驱动在展开二进制格式反连串化时亦会实行项目检查。所以反连串化时的运转条件要与种类化时的运维条件要一致,否者恐怕会不大概反连串化成功。

澳门葡京备用网址 41澳门葡京备用网址 42

     
  作用基本达成了,上面比较一下一千0次的实业种类化与反种类化测试结果:

澳门葡京备用网址 ,3.运用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 [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系列化无法种类化泛型类型。与2进制体系化同样在系列化时不须求向系列化器钦命连串化对象的品类。而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();

        运营结果:

四.用到XML情势连串化和反体系化

View Code

澳门葡京备用网址 49 

(一)XML体系化与反系列化的先后示例

最后说一下明日本人在做Json类别化时,蒙受的三个主题材料:在写出类名JavaScriptSerializer后怎么都无法引用(类名也不会变浅青),在网络查了下,终于找到方法(小编用的是Visual
Studio 20十,二零一一也十分):

澳门葡京备用网址 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]特性。

5.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>

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

类声明:  

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

体系化生成的XML文件:

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

(6)列表和数组的系列化

类声明:

澳门葡京备用网址 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姓名="李志伟"性别="男" />

(1二)连串化设置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>

(13)XML的应用建议

在服务端,C#代码中:

壹. 建议并非选拔低等其余XML
API来利用XML,除非你是在筹算框架大概通用类库。

二. 建议利用种类化、反连串化的不二等秘书诀来扭转依然读取XML

3. 当供给思量使用XML时,先不要想着XML结构,先应该定义好数据类型。

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

五. 万一期望类别化的XML长度小一些,可以动用[XmlAttribute],恐怕钦定1个更加短小的别称。

陆. 毫无在3个列表中输出不相同的数据类型,那样的XML结构的可读性不佳。

7. 竭尽选拔UTF-捌编码,不要使用GB231贰编码。

在客户端,JavaScript代码中,小编不建议选择XML,而是建议选用JSON来替代XML,因为:

一.
XML文书的尺寸比JSON要长,会占用越来越多的网络传输时间(毕竟数据保存在服务端,所以传输是免不了的)。

二. 在JavaScritp中运用XML比较辛勤(还有浏览器的包容难点),反而各个浏览器对JSON有充足好的支撑。

(1四)反类别化的使用计算

万一XML是由项目系列化得到那的,那么反类别化的调用代码是很简短的,反之,如果要面对二个尚未项目的XML,就必要大家先规划3个(可能部分)类型出来,那是一个逆向推导的进程,请参见以下步骤:

一. 首先要分析任何XML结构,定义与之同盟的类型,

二. 只要XML结构有嵌套档次,则必要定义七个种类与之协作,

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

XML形式

处理方法

补充说明

XmlElement

定义一个属性

属性名与节点名字匹配

XmlAttribute

[XmlAttribute] 加到属性上

 

InnerText

[InnerText] 加到属性上

一个类型只能使用一次

 

 

节点重命名

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

 

陆.自定义连串化(仅适用于贰进制与SOAP)

(一)自定义体系化的贯彻格局

可以透过在对象上落到实处 ISerializable 接口来自定义类别化进程。这一职能在反连串化后成员变量的值失效时特别有用,然则急需为变量提供值以重建对象的一体化气象。要贯彻ISerializable,须求达成 GetObjectData()方法以及1个相当的构造函数,在反系列化对象时要用到此构造函数。

(2)示例程序   

澳门葡京备用网址 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()时,须要填写方法调用中提供的SerializationInfo对象。只需按名称/值对的款型丰裕就要种类化的变量。其名目能够是别的公文。只要已体系化的数量能够在反种类化进程中恢复生机对象,便能够自由选取增多至塞里alizationInfo 的成员变量。要是基对象落成了 ISerializable,则派生类应调用其基对象的 GetObjectData()方法。一样,在反序列化时也会调用含有(SerializationInfo info, StreamingContextcontext)参数的不相同平日的够着法子!否者将无法反体系化!!!

相关文章

发表评论

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

*
*
Website