浅谈C#中的序列化与反序列化
今天我利用这篇文章给大家讲解一下C#中的序列化与反序列化。这两个概念我们再开发中经常用到,但是我们绝大部分只用到了其中的一部分,剩下的部分很多开发人员并不清楚,甚至可以说是不知道。因此我希望通过这篇文章能让大家对序列化和反序列化的知识有更进一步的掌握。废话不多说,开始进入正题。
一、什么是序列化/反序列化
在所有的开发语言中都存在序列化和反序列化这个概念,所谓的序列化就是把一个对象信息转化为一个可以持久存储的数据形式,经过转化后就可以方便的保存和传输了,因此序列化主要用于平台之间的通讯。由于序列化我们可以反推出所谓的反序列化就是将持久存储的数据还原为对象。
二、C#中的序列化/反序列化
在C#中我们经常会对Json和Xml进行序列化和反序列化,但是还存在一种序列化/反序列化,那就是将对象序列化为二进制文件,将二进制文件反序列化为对象。下面我会对这三种序列化和反序列化进行解释。
1、Json
Json的英文全称是JavaScript Object Notation,是一种轻量级的数据交换格式,完全独立于语言的文本格式,易于人阅读和编写,同时也易于机器解析和生成。Json是目前互联网中主流的交换格式,同时也是很多开发语言配置文件的主流格式。
在.Net中存在两个类对Json进行处理,分别是DataContractJsonSerializer和JavaScriptSerializer,这两种类的功能基本一致。DataContractJsonSerializer位于命名空间 System.Runtime.Serialization.Json下,他的特点是必须用DatContract以及DataMember属性标记成员。JavaScriptSerializer位于命名空间System.Web.Script.Serialization下,通过名字和他所在的命名空间我们可以得知他主要用在网络通信中,他可以序列化任何类型的对象。同样.Net中也存在一个强大的第三方Json序列化/反序列化库 Newtonsoft.Json,他比前两个类用起来方便很多。下面我们对这三个序列化/反序列化的方式分别进行讲解。
(1)DataContractJsonSerializer
首先我们需要在项目引用DataContractJsonSerializer所在的命名空间,这里主要注意的是我们不仅要在项目中添加System.Runtime.Serialization还需要添加引用System.ServiceModel.Web。将这两个命名空间添加到命名空间后就可以在代码中进入DataContractJsonSerializer的命名空间了。
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
引入命名空间后,我们开始编写序列化类
[DataContract]
class Student
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Sex { get; set; }
[DataMember]
public int Age { get; set; }
[DataMember]
public Address Address { get; set; }
} [DataContract]
class Address
{
[DataMember]
public string City { get; set; }
[DataMember]
public string Road { get; set; }
}
在上述代码中,我们看到类的头部添加了DataContract特性,以及在类的属性上也增加了DataMenber特性,一旦一个类被声明为DataCOntract时,就代表着该类可以被序列化,并且可以在服务端和客户端传输。只有声明为DataContract的类型的对象可以被传送,而且只有成员属性会被传送,成员方法不会被传送。默认情况下类中的所有成员属性都不会被序列化传输出去,如果需要将成员数据传输出去就需要在属性头部加入DataMember。
下面我们就利用DataContractJsonSerializer对对象进行序列化和反序列化,代码如下:
class Program
{
static void Main()
{
#region 对象转Json字符串 var student = new Student
{
Name = "小魔王",
Age = ,
Sex = ,
Address = new Address
{
City = "SD",
Road = "JS"
}
}; //利用WriteObject方法序列化Json
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Student));
var stream = new MemoryStream();
serializer.WriteObject(stream, student);
var bytes = new byte[stream.Length];
stream.Position = ;
stream.Read(bytes, , (int)stream.Length);
var strJson = Encoding.UTF8.GetString(bytes);
Console.WriteLine(strJson); #endregion #region Json字符串转对象 stream = new MemoryStream(Encoding.UTF8.GetBytes(strJson));
student = (Student)serializer.ReadObject(stream);
Console.WriteLine($"Name:{student.Name}");
Console.WriteLine($"Sex:{student.Sex}");
Console.WriteLine($"Age:{student.Age}");
Console.WriteLine($"Address:{student.Address.City}{student.Address.Road}"); #endregion Console.ReadKey();
}
} [DataContract]
class Student
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Sex { get; set; }
[DataMember]
public int Age { get; set; }
[DataMember]
public Address Address { get; set; }
} [DataContract]
class Address
{
[DataMember]
public string City { get; set; }
[DataMember]
public string Road { get; set; }
}
结果:

(2)JavaScriptSerializer
我们利用前面定义的类,来看一下JavaScriptSerializer的使用方法,我们将前面定义的类中的DataContract和DataMember都去掉。我们如果要使用JavaScriptSerializer只需要引入System.Web.Script.Serialization命名空间即可。下面我们就利用JavaScriptSerializer对象进行序列化和反序列化,代码如下:
static void Main()
{
#region 对象转Json字符串 var student = new Student
{
Name = "小魔王",
Age = ,
Sex = ,
Address = new Address
{
City = "SD",
Road = "JS"
}
}; //初始化
JavaScriptSerializer serializer = new JavaScriptSerializer();
var strJson = serializer.Serialize(student);
Console.WriteLine(strJson);
#endregion #region Json字符串转对象 student = serializer.Deserialize<Student>(strJson);
Console.WriteLine($"Name:{student.Name}");
Console.WriteLine($"Sex:{student.Sex}");
Console.WriteLine($"Age:{student.Age}");
Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}");
#endregion Console.ReadKey();
}
} class Student
{
public string Name { get; set; }
public int Sex { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
} class Address
{
public string City { get; set; }
public string Road { get; set; }
}
结果:

(3)Newtonsoft.Json
NewtonSoft.Json功能有很多,除了序列化和反序列化之外,还有 Linq To Json、Json Path、XML support等,我们这篇文章之讲解其中的序列化和反序列化,使用NewtonSoft.Json前首先我们需要在nuget中搜索并安装,安装完成后引入NewtonSoft.Json,下面我么你来看一下具体使用:
class Program
{
static void Main()
{
#region 对象转XML字符串 var student = new Student
{
Name = "小魔王",
Age = ,
Sex = ,
Address = new Address
{
City = "SD",
Road = "JS"
}
}; //初始化
var strJson = JsonConvert.SerializeObject(student);
Console.WriteLine(strJson);
#endregion #region Json字符串转对象 student = JsonConvert.DeserializeObject<Student>(strJson);
Console.WriteLine($"Name:{student.Name}");
Console.WriteLine($"Sex:{student.Sex}");
Console.WriteLine($"Age:{student.Age}");
Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}");
#endregion Console.ReadKey();
}
} class Student
{
public string Name { get; set; }
public int Sex { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
} class Address
{
public string City { get; set; }
public string Road { get; set; }
}
结果:

从代码中我们可以看到 NewtonSoft.Json序列化和反序列化更加简单,简单到只需要一行代码就可以完成。
2、XML
在Json还没有出现之前,Xml是互联网上常用的数据交换格式和规范。.net中提供XmlSerializer类将对象序列化为XML和将XML反序列化为对象,使用方法是首先实例化,然后调用序列化/反序列化方法。下面我们依然使用最开始定义的那个类,来看看XmlSerializer的使用。使用前我们需要引入using System.Xml.Serialization命名空间。
具体序列化与反序列化方法如下:
class Program
{
static void Main()
{
#region 对象转XML字符串 var student = new Student
{
Name = "小魔王",
Age = ,
Sex = ,
Address = new Address
{
City = "SD",
Road = "JS"
}
}; //初始化
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student));
using (var fs = new FileStream(@"F:\123.xml", FileMode.OpenOrCreate))
{
xmlSerializer.Serialize(fs, student);
}
Console.WriteLine("序列化完成");
#endregion #region Json字符串转对象 using (var fs = new FileStream(@"F:\123.xml", FileMode.OpenOrCreate))
{
//XmlReader xmlReader = new XmlTextReader(fs);
//student = xmlSerializer.Deserialize(xmlReader) as Student;
student = xmlSerializer.Deserialize(fs) as Student;
}
Console.WriteLine($"Name:{student.Name}");
Console.WriteLine($"Sex:{student.Sex}");
Console.WriteLine($"Age:{student.Age}");
Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}");
#endregion Console.ReadKey();
}
} public class Student
{
public string Name { get; set; }
public int Sex { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
} public class Address
{
public string City { get; set; }
public string Road { get; set; }
}
结果:


3、二进制
序列化为二进制,在实际开发中真有不少用到,但是我觉得还是有必要讲一讲,他的使用方法和XmlSerializer序列化/反序列化类似,首先实例化,然后调用序列化/反序列化方法。在进行序列化/反序列化前,首先引入命名空间System.Runtime.Serialization.Formatters.Binary,同时修改对象类如下:
[Serializable]
public class Student
{
public string Name { get; set; }
public int Sex { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
} [Serializable]
public class Address
{
public string City { get; set; }
public string Road { get; set; }
}
上述代码中我们在类的头部加入了Serializable特性,这代表着整个类对象都需要序列化,如果我们不需要序列化其中的某个属性的话,只需要在该属性上加上NonSerialized特性即可,下面我们来看一下序列化/反序列化代码:
class Program
{
static void Main()
{
#region 对象转XML字符串 var student = new Student
{
Name = "小魔王",
Age = ,
Sex = ,
Address = new Address
{
City = "SD",
Road = "JS"
}
}; BinaryFormatter binaryFormatter = new BinaryFormatter();
string fileName = Path.Combine(@"F:\", @"123.txt");
using (var stream = new FileStream(fileName, FileMode.OpenOrCreate))
{
binaryFormatter.Serialize(stream, student);
}
Console.WriteLine("序列化完成");
#endregion #region 字符串转对象 using (var fs = new FileStream(@"F:\123.txt", FileMode.OpenOrCreate))
{
student = binaryFormatter.Deserialize(fs) as Student;
}
Console.WriteLine($"Name:{student.Name}");
Console.WriteLine($"Sex:{student.Sex}");
Console.WriteLine($"Age:{student.Age}");
Console.WriteLine($"Address:{student.Address.City}+{student.Address.Road}");
#endregion Console.ReadKey();
}
} [Serializable]
public class Student
{
public string Name { get; set; }
public int Sex { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
} [Serializable]
public class Address
{
public string City { get; set; }
public string Road { get; set; }
}
这篇文章详细的讲述了.Net中序列化与反序列化的相关知识和使用,序列化和反序列化的相关知识还有很多,这里所讲的都是开发中常用到的。好了,今天的知识就分享到这里了。
浅谈C#中的序列化与反序列化的更多相关文章
- 在net中json序列化与反序列化 面向对象六大原则 (第一篇) 一步一步带你了解linq to Object 10分钟浅谈泛型协变与逆变
在net中json序列化与反序列化 准备好饮料,我们一起来玩玩JSON,什么是Json:一种数据表示形式,JSON:JavaScript Object Notation对象表示法 Json语法规则 ...
- 浅谈jQuery中的Ajax
浅谈jQuery中的Ajax 一.前言 jQuery 对 Ajax 操作进行了封装, 在 jQuery 中最底层的方法时 $.ajax(), 第二层是 load(), $.get() 和 $.post ...
- 浅谈Java中的equals和==(转)
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- 浅谈Java中的对象和引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
- 浅谈Java中的equals和==
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...
- 转【】浅谈sql中的in与not in,exists与not exists的区别_
浅谈sql中的in与not in,exists与not exists的区别 1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表 ...
- 浅谈iOS中的userAgent
浅谈iOS中的userAgent User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
随机推荐
- Linux的中断可以嵌套吗?
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 来源: 微信公众号linux阅码场(id: linuxdev) 问答 问:Linux的中断可以嵌套吗? 答:以前是可以 ...
- 工具类 ,无需再存localstorage
/** * 工具类 */var Utils = { /** * 获得查询参数 */ getQueryString: function(name) { var search = location.sea ...
- JDK下载安装配置教程(详细)
JDK下载安装配置教程(详细) 版权声明:本文为原创文章,转载请附上原文出处链接和本声明.https://www.cnblogs.com/mxxbc/p/11844885.html 因为最近需要在Wi ...
- day5-基本数据类型总结
一.数字int(..)二.字符串replace/find/join/strip/startswith/split/upper/lower/format tempalte = "i am {n ...
- W与V模型的联系与区别
很多小白一定要注意: 看准那个是开发的工作哪个是测试的工作,不要弄混了!!! 软件测试的V模型 以“编码”为黄金分割线,将整个过程分为开发和测试,并且开发和测试之间是串行的关系 ...
- C++中对封装的语法支持——this指针
this指针 1.this概念 (1) This指针就是用于成员函数区分调用对象. (2) This指针由编译器自动传递,无须手动传递,函数内部隐藏了this指针参数,本类类型的指针. (3) 编译器 ...
- ubantu14.04安装storm伪分布式
1.安装jdk 安装:sudo apt-get install openjdk-7-jdk 配置: 修改文件 sudo nano /etc/profile , 添加以下内容: 立即执行使之生效: 2. ...
- 力扣(LeetCode)字符串中的单词数 个人题解
统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符. 请注意,你可以假定字符串里不包括任何不可打印的字符. 示例: 输入: "Hello, my name is John" ...
- C语言|博客作业09
这个作业属于哪个课程 C语言程序设计II 这个作业的要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-1/homework/10027 我在这个课程 ...
- QTabWidget 头部背景色设置和QTabWidget 样式设置
1.问题:QTabWiget的头部背景色通过设置background-color属性没有生效,网上找了很多方法,也不生效. 2.解决办法:在Qt Designer中将autoFillBackgroun ...