C# 序列化器

理论知识:

序列化是指将对象转换成字节流,从而存储对象或将对象传输到内存、数据库或文件的过程。 它的主要用途是保存对象的状态,以便能够在需要时重新创建对象。 反向过程称为“反序列化”。

序列化的工作原理

下图展示了序列化的整个过程:

图:序列化

将对象序列化为带有数据的流。 该流还可能包含有关对象类型的信息,例如其版本、区域性和程序集名称。 可以将此流中的对象存储在数据库、文件或内存中。

序列化的用途

通过序列化,开发人员可以保存对象的状态,并能在需要时重新创建对象,同时还能存储对象和交换数据。 通过序列化,开发人员可以执行如下操作:

  • 使用 Web 服务将对象发送到远程应用程序
  • 将对象从一个域传递到另一个域
  • 将对象通过防火墙传递为 JSON 或 XML 字符串
  • 跨应用程序维护安全或用户特定的信息

JSON 序列化

System.Text.Json 命名空间包含用于 JavaScript 对象表示法 (JSON) 序列化和反序列化的类。 JSON 是一种常用于在 Web 上共享数据的开放标准。

JSON 序列化将对象的公共属性序列化为符合 RFC 8259 JSON 规范的字符串、字节数组或流。 若要控制 JsonSerializer 对类的实例进行序列化或反序列化的方法,请执行以下操作:

二进制和 XML 序列化

System.Runtime.Serialization 命名空间包含用于对二进制和 XML 进行序列化和反序列化的类。

二进制序列化使用二进制编码来生成精简的序列化以供使用,如基于存储或套接字的网络流。 在二进制序列化中,所有成员(包括只读成员)都会被序列化,且性能也会有所提升。

XML 序列化将对象的公共字段和属性或方法的参数和返回值序列化成符合特定 XML 架构定义语言 (XSD) 文档要求的 XML 流。 XML 序列化生成已转换成 XML 的强类型类,其中包含公共属性和字段。 System.Xml.Serialization 包含用于对 XML 进行序列化和反序列化的类。 将特性应用于类和类成员,从而控制 XmlSerializer 如何序列化或反序列化类的实例。

让对象可序列化

若要对二进制或 XML 进行序列化,你需要:

将 SerializableAttribute 特性应用于某个类型,以指示可对此类型进行序列化的实例。 如果尝试对没有 SerializableAttribute 特性的类型进行序列化,则会引发异常。

若要防止对字段进行序列化,请应用 NonSerializedAttribute 特性。 如果可序列化的类型中的一个字段包含指针、句柄或特定环境专用的其他一些数据结构,且不能在其他环境中有意义地重构,不妨让其不可序列化。

如果已序列化的类引用被标记为 SerializableAttribute 的其他类的对象,那么这些对象也会被序列化。

基本和自定义序列化

可以使用两种方法对二进制和 XML 进行序列化:基本和自定义。

基本序列化使用 .NET Framework 自动序列化对象。 唯一的要求是类应用 SerializableAttribute 特性。 NonSerializedAttribute 可用于防止特定字段被序列化。

使用基本序列化时,对象的版本控制可能会产生问题。 对于重要的版本控制问题,可以使用自定义序列化。 基本序列化是最简单的序列化执行方式,但无法提供太多的进程控制。

在自定义序列化中,可以精确指定要序列化的对象以及具体执行方式。 类必须被标记为 SerializableAttribute,并实现 ISerializable 接口。 如果还希望按自定义方式反序列化对象,请使用自定义构造函数。

设计器序列化

设计器序列化是一种特殊形式的序列化,涉及与开发工具相关联的对象暂留。 设计器序列化是指将对象图转换成源文件以供日后用于恢复对象图的过程。 源文件可以包含代码、标记或 SQL 表信息。

 

 

演示代码

数据准备

    [Serializable]  //必须添加序列化特性
    public class Person
    {
        [NonSerialized]
        public int Id = 1;

        public string Name { get; set; }

        public string Sex { get; set; }
    }

    [Serializable]  //必须添加序列化特性
    public class Programmer : Person
    {
        private string Language { get; set; }//编程语言
        public string Description { get; set; }
    }

    public class DataFactory
    {
        /// <summary>
        /// 初始化数据的
        /// </summary>
        /// <returns></returns>
        public static List<Programmer> BuildProgrammerList()
        {
            #region data prepare
            List<Programmer> list = new List<Programmer>();
            list.Add(new Programmer()
            {
                Id = 1,
                Description="高级班学员",
                Name = "SoWhat",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "day",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "领悟",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "Sam",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "AlphaGo",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "折腾",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "Me860",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "打兔子的猎人",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "Nine",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "微笑刺客",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "waltz",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "爱在昨天",
                Sex = ""
            });
            list.Add(new Programmer()
            {
                Id = 1,
                Description = "高级班学员",
                Name = "waltz",
                Sex = ""
            });
            #endregion

            return list;
        }
    }
二进制序列化器
可以对单个对象或集合对象(如List<T>、ObservableCollection<T>)进行序列化。需要指出的是,需要对被序列化的对象添加[Serializable]特性
  /// <summary>
        /// 二进制序列化器
        /// </summary>
        public static void BinarySerialize()
        {
            //使用二进制序列化对象
            string fileName = Path.Combine(Constant.SerializeDataPath, @"BinarySerialize.txt");//文件名称与路径
            using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
            {//需要一个stream,这里是直接写入文件了
                List<Programmer> pList = DataFactory.BuildProgrammerList();
                BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器
                binFormat.Serialize(fStream, pList);
            }
            using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
            {//需要一个stream,这里是来源于文件
                BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器
                //使用二进制反序列化对象
                fStream.Position = 0;//重置流位置
                List<Programmer> pList = (List<Programmer>)binFormat.Deserialize(fStream);//反序列化对象
            }
        }

soap序列化器

可以对单个对象进行序列化。但是,很大的缺陷在于,不能直接对泛型集合数据(如List<T>、ObservableCollection<T>)进行序列化(注:无论是根对象就是泛型集合,还是某个对象下的字段或属性是泛型集合,都不能序列化),
而要使用BinaryFormatter或XmlSerializer进行序列化。由于无法对泛型集合对象进行序列化,因此使用面比较窄,个人不建议使用SoapFormatter
 /// <summary>
        /// soap序列化器
        /// </summary>
        public static void SoapSerialize()
        {
            //使用Soap序列化对象
            string fileName = Path.Combine(Constant.SerializeDataPath, @"SoapSerialize.txt");//文件名称与路径
            using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
            {
                List<Programmer> pList = DataFactory.BuildProgrammerList();
                SoapFormatter soapFormat = new SoapFormatter();//创建二进制序列化器
                //soapFormat.Serialize(fStream, list);//SOAP不能序列化泛型对象
                soapFormat.Serialize(fStream, pList.ToArray());
            }
            using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
            {
                SoapFormatter soapFormat = new SoapFormatter();//创建二进制序列化器
                //使用二进制反序列化对象
                fStream.Position = 0;//重置流位置
                List<Programmer> pList = ((Programmer[])soapFormat.Deserialize(fStream)).ToList();//反序列化对象
            }
        }
 XML序列化器
无论对于单个对象还是集合对象(如List<T>、ObservableCollection<T>),都可以使用XmlSerializer进行序列化。需要指出的是,不需要对被序列化的对象添加[Serializable]特性注解。但是,使用XmlSeriabizable
的时候,被序列化的对象应该具有无参数构造函数。
 /// <summary>
        /// XML序列化器
        /// </summary>
        public static void XmlSerialize()
        {
            //使用XML序列化对象
            string fileName = Path.Combine(Constant.SerializeDataPath, @"Student.xml");//文件名称与路径
            using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
            {
                List<Programmer> pList = DataFactory.BuildProgrammerList();
                XmlSerializer xmlFormat = new XmlSerializer(typeof(List<Programmer>));//创建XML序列化器,需要指定对象的类型
                xmlFormat.Serialize(fStream, pList);
            }
            using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
            {
                XmlSerializer xmlFormat = new XmlSerializer(typeof(List<Programmer>));//创建XML序列化器,需要指定对象的类型
                //使用XML反序列化对象
                fStream.Position = 0;//重置流位置
                List<Programmer> pList = pList = (List<Programmer>)xmlFormat.Deserialize(fStream);
            }
        }

Json序列化

目前业界,普通都采用此方式,优点很多,大家百度吧

    public class JsonHelper
    {
        #region Json
        /// <summary>
        /// JavaScriptSerializer
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ObjectToString<T>(T obj)
        {
            JavaScriptSerializer jss = new JavaScriptSerializer();
            return jss.Serialize(obj);
        }

        /// <summary>
        /// JavaScriptSerializer
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="content"></param>
        /// <returns></returns>
        public static T StringToObject<T>(string content)
        {
            JavaScriptSerializer jss = new JavaScriptSerializer();
            return jss.Deserialize<T>(content);
        }

        /// <summary>
        /// JsonConvert.SerializeObject
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJson<T>(T obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// JsonConvert.DeserializeObject
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="content"></param>
        /// <returns></returns>
        public static T ToObject<T>(string content)
        {
            return JsonConvert.DeserializeObject<T>(content);
        }
        #endregion Json
    }

补充说明

****非常重要****。需要说明的是,反序列化的过程(从文件-->对象的过程),不是new出来新对象,然后对其进行赋值的。反序列化的时候,不是依据类代码对各个成员进行初步赋值,然后执行构造函数的过程。在反序列化的时候,既不会为成员初赋值,也不会执行构造函数,而是直接对没有标注为[NonSerialized]的字段赋给其保存在文件中的值,而对于标注为[NonSerialized]的字段,其结果仅仅是default(FiledType),此处的FieldType是指字段的类型(注:可以利用OnSerialized方法来事后修改字段的值)。例如:

[Serializable]

public class MyClass

{

        public MyClass()

        {

            //在反序列化的时候,不会执行构造函数

        }

        private int x=10;   //在反序列化的时候,不是将10赋值给x。而是从数据文件中读取相应的值,直接赋值给x。

       [NonSerializable]

       private int y=15;   //在反序列化的时候,不会将15赋值给y。由于y标注了[NonSerializable],因此,反序列化完成的时候,y的值是default(int),也就是0。

        private List<string> Strs=new List<string>();  //在反序列化的时候,不会new一个将List<string>并且赋值给Strs。而是从数据文件中读取相应的值,直接赋值给Strs。

       [NonSerializable]

        private List<string> AnotherStrs=new List<string>();  //在反序列化的时候,不会new一个List<string>并且将其赋值给AnotherStrs。由于AnotherStrs标注了[NonSerializable],因此,反序列化完成的时候,AnotherStrs的值是default(List<string>),也就是null。

}

 

参考资料:、

http://www.cppcns.com/ruanjian/csharp/115791.html
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/serialization/
https://blog.csdn.net/jiuzaizuotian2014/article/details/80974583 朝夕教育eleven老师演示代码

  

 

posted @ 2020-03-04 17:16  明志德道  阅读(395)  评论(0编辑  收藏  举报