您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

开发者应当熟知的 C# 序列化和反序列化

时间:2019-11-06 10:13:40  来源:  作者:
开发者应当熟知的 C# 序列化和反序列化

作者 | 喵叔

责编 | 刘静

出品 | CSDN(ID:CSDNnews)

今天我利用这篇文章给大家讲解一下 C# 中的序列化与反序列化。这两个概念我们在开发中经常用到,但是我们绝大部分只用到了其中的一部分,剩下的部分很多开发人员并不清楚,伸着可以说是不知道。因此我希望通过这篇文章能让各位对序列化和反序列化的知识有更进一步的掌握。废话不多说开始进入正题。
 

1.什么是序列化/反序列化

在所有的开发语言中都存在序列化和反序列化这个概念,所谓的序列化就是把一个对象信息转化为一个可以持久存储的数据形式,经过转化后就可以方便的保存和传输了,因此序列化主要用于平台之间的通讯。由序列化我们可以反推出所谓的反序列化就是将持久存储的数据还原为对象。

 

2.C# 中的序列化/反序列化

在 C# 中我们经常会对 JSON 和 XML 进行序列化和反序列化 ,但是还有存在一种序列化/反序列化,那就是将对象序列化为二进制文件,将会二进制文件反序列化为对象。下面我将会对这三种序列化和反序列化进行讲解。

1. JSON

JSON 的英文全称是 JAVAScript Object Notation ,是一种轻量级的数据交换格式。完全独立于语言的文本格式 易于人阅读和编写同时也易于机器解析和生成。JSON 是目前互联网中主流的数据交换格式,同时也是很多开发语言配置文件的主流格式。

在 .NET 中存在两个类对 JSON 进行处理,分别是 DataContractJsonSerializer 和 JavaScriptSerializer ,这两个类的功能基本一致。DataContractJsonSerializer 位于命名空间 System.Runtime.Serialization.Json 下,它的特点是必须使用 DataContract 以及 DataMember 属性标记成员。JavaScriptSerializer 位于命名空间 System.Web.Script.Serialization 下,通过名字和它所在的命名空间我们可以得知它主要用在网络通信中,它可以序列化任何类型的对象。同样 .NET 中也存在一个强大的第三方 JSON 序列化/反序列化库 Newtonsoft.Json ,他比前两个类用起来要方便很多。下面我们对这三个序列化/反序列化的方式分别进行讲解。

  • 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 特性,以及在类的属性上也增加了 DataMember 特性 。一旦一个类被声明为 DataContract 时就代表着该类可以被序列化,并且可以在服务端和客户端传输。只有声明为DataContract的类型的对象可以被传送,且只有成员属性会被传递,成员方法不会被传递。默认情况下类中的所有成员属性都不会被序列化传输出去,如果需要将成员数据传输出去就需要在属性头部加入 DataMember 。

下面我们就利用 DataContractJsonSerializer 对对象尽心序列化和反序列化,代码如下

class Program
{
static void Main(string[] args)
{
#region 对象转JSON字符串
Student student = new Student
{
Name = "Tom",
Age = 20,
Sex = 1,
Address = new Address
{
City = "NYC",
Road = "ABC"
}
};
//利用WriteObject方法序列化为 JSON
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Student));
MemoryStream stream = new MemoryStream;
serializer.WriteObject(stream, student);
byte bytes=new byte[stream.Length];
stream.Position = 0;
stream.Read(bytes, 0, (int)stream.Length);
string jsonStr = Encoding.UTF8.GetString(bytes);
Console.WriteLine(jsonStr);
#endregion

#region JSON字符串转对象
stream = new MemoryStream(Encoding.Default.GetBytes(jsonStr));
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.ReadLine;
}
}

输出结果如下:

开发者应当熟知的 C# 序列化和反序列化
  • JavaScriptSerializer

我们利用前面定义的类,来看一下 JavaScriptSerializer 的使用方法,我们将前面定义的类中的 DataContract 和 DataMember 都去掉。我们如果要使用 JavaScriptSerializer 只需引入 System.Web.Script.Serialization 命名空间即可。代码如下:

using System.Web.Script.Serialization;

下面我们就利用 JavaScriptSerializer 对象进行序列化和反序列化,代码如下:

class Program
{
static void Main(string[] args)
{
#region 序列化
Student student = new Student
{
Name = "Tom",
Age = 20,
Sex = 1,
Address = new Address
{
City = "NYC",
Road = "ABC"
}
};
//初始化
JavaScriptSerializer serializer = new JavaScriptSerializer;
string jsonStr = serializer.Serialize(student);
Console.WriteLine(jsonStr);
#endregion

#region 反序列化
student = serializer.Deserialize<Student>(jsonStr);
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.ReadLine;
}
}

从上面的代码我们可以看出利用 JavaScriptSerializer 序列化和反序列化要比 DataContractJsonSerializer 类方便。上述代码运行结果如下:

开发者应当熟知的 C# 序列化和反序列化
  • Newtonsoft.Json

Newtonsoft.Json 功能有很多,除了序列化反序列化之外,还有 Linq To Json、Json Path、 XML support等,我们这篇文章我们只讲解其中的序列化和反序列化。使用 Newtonsoft.Json 前首先我们需要在 nuget 中搜索并安装,安装完成后引入 Newtonsoft.Json,代码如下:

using Newtonsoft.Json;

下面我们来看看 Newtonsoft.Json 的具体使用:

class Program
{
static void Main(string[] args)
{
#region 序列化
Student student = new Student
{
Name = "Tom",
Age = 20,
Sex = 1,
Address = new Address
{
City = "NYC",
Road = "ABC"
}
};
string jsonStr = JsonConvert.SerializeObject(student);
Console.WriteLine(jsonStr);
#endregion

#region 反序列化
student = JsonConvert.DeserializeObject<Student>(jsonStr);
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.ReadLine;
}
}

上述代码输出结果如下:

开发者应当熟知的 C# 序列化和反序列化

从代码中我们看到 Newtonsoft.Json 序列化和反序列化更加简单,简单到只需要一行代码就完成了序列化和反序列化。

2. XML

在 JSON 还没出现之前,XML 是互联网上常用的数据交换格式和规范。.NET 中提供 XmlSerializer 类将对象序列化为 XML 和将 XML 反序列化为对象,使用方法是首先实例化,然后调用序列化/反序列化方法。下面我们依然使用最开始定义的那个类,来看看 XmlSerializer 的使用。使用前我们需要引入 using System.Xml.Serialization 命名空间。

using System.Xml.Serialization;

具体序列化/反序列化方法如下:

class Program
{
static void Main(string[] args)
{
#region 序列化
Student student = new Student
{
Name = "Tom",
Age = 20,
Sex = 1,
Address = new Address
{
City = "NYC",
Road = "ABC"
}
};
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Student));
using (FileStream stream = new FileStream(@"d:123.xml", FileMode.OpenOrCreate))
{
xmlSerializer.Serialize(stream, student);
}
#endregion

#region 反序列化
using (FileStream stream = new FileStream(@"d:123.xml", FileMode.OpenOrCreate))
{
XmlReader xmlReader = new XmlTextReader(stream);
student = xmlSerializer.Deserialize(xmlReader) 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.ReadLine;
}
}

这里有一点需要注意,如果对象类的访问修饰符不是 public 将会报错。上述代码运行结果如下:

开发者应当熟知的 C# 序列化和反序列化

开发者应当熟知的 C# 序列化和反序列化

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(string[] args)
{
#region 序列化
Student student = new Student
{
Name = "Tom",
Age = 20,
Sex = 1,
Address = new Address
{
City = "NYC",
Road = "ABC"
}
};
BinaryFormatter binFormat = new BinaryFormatter;
string fileName = Path.Combine(@"D:", @"321.txt");
using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
{
binFormat.Serialize(fStream, student);
}
#endregion

#region 反序列化
using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite))
{
fStream.Position = 0;
student = (Student)binFormat.Deserialize(fStream);
}
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.ReadLine;
}
}

上述代码最终输出结果如下:

开发者应当熟知的 C# 序列化和反序列化

3.总结

这篇文章详细讲解了.NET中序列化和反序列化相关知识的使用,序列化和反序列化相关的只是还有很多,这里所讲解的都是开发中经常用到的,也是面试过程中会提及的,因此大家需要牢记。

作者简介:朱钢,笔名喵叔,CSDN博客专家,.NET高级开发工程师,7年一线开发经验,参与过电子政务系统和AI客服系统的开发,以及互联网招聘网站架构设计,目前就职于北京恒创融慧科技发展有限公司,从事企业级安全监控系统的开发。

声明:本文系作者独立观点,不代表CSDN立场。



Tags:C#   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除,谢谢。
▌相关推荐
在实际的项目开发中,可能需要考虑代码的安全性或执行效率,需要将具体的功能实现隐藏,dll接口提供了很好的解决方案。dll接口不仅在C++的项目中可以直接调用,在C#开发的项目也同...【详细内容】
2021-07-09  Tags: C#  点击:(7)  评论:(0)  加入收藏
作为程序员吃饭的工具,编程语言之间也形成了某种鄙视链,各大论坛里弥漫着剑拔弩张的气氛,众口难调。也难怪有很多初学者会有疑惑,为什么会有这么多编程语言,我到底应该学什么语言...【详细内容】
2021-06-29  Tags: C#  点击:(13)  评论:(0)  加入收藏
我是笑林新记,分享一下我使用C#的一些用法,希望对大家有帮助!欢迎关注:笑林新记Visual Studio版本:Enterprise 2015.net Framework版本:3.51Socket介绍 有粉丝私信说让讲一下局域...【详细内容】
2021-06-28  Tags: C#  点击:(16)  评论:(0)  加入收藏
开发工具:vs 2017AI 平台:http://ai.baidu.com/准备工作1、注册百度账号2、登录百度 AI 开发平台,http://ai.baidu.com/3、在控制台点击“百度语音”服务,点击“创建应用”,填写...【详细内容】
2021-06-10  Tags: C#  点击:(36)  评论:(0)  加入收藏
前言本来因为懒不想写这篇文章,但是不少人表示有兴趣,于是最后决定还是写一下。.NET 6 最近几个预览版一直都在开发体验(如 hot reload、linker 等)、平台支持(如 Android、iOS...【详细内容】
2021-06-07  Tags: C#  点击:(26)  评论:(0)  加入收藏
  2021年4月19日微软发布公告称将于今年夏季发布首款64位的 Visual Studio 2022,2021年5月20日又发布了 Visual Studio 2022 线路图,进一步提升开发生产力。与 Visual Stud...【详细内容】
2021-06-03  Tags: C#  点击:(79)  评论:(0)  加入收藏
1、功能需求本实例将通过c# winform实现简单的分页功能,需要的基础知识有SQL语句,c#语言基础以及c# winform的一些简单知识。2、界面设计这是一个简单的分页查询的界面,可以输...【详细内容】
2021-02-25  Tags: C#  点击:(91)  评论:(0)  加入收藏
在你的 .NET 程序中经常会记录一些日志或者错误,为了实现这个功能,你可能会使用市面上那些现成的日志框架(log4net,nlog ...),当然你也可以设计并开发一个自己的日志框架,在这篇文...【详细内容】
2020-12-22  Tags: C#  点击:(88)  评论:(0)  加入收藏
大家都知道手机、车机、小爱同学、人机对话渗入大家的生活。那么工控领域C#上位机#和 #PLC#是不是也可以人机对话呢?今天我们用WPF实现一下。硬件:S7-1200软件:C#库文件:System....【详细内容】
2020-12-14  Tags: C#  点击:(61)  评论:(0)  加入收藏
前面有几篇文章,已经教了一些方式或者方法,帮助您摆脱娘胎自带的面向过程编程,从而转为面向对象。本文讲一下面向对象依赖倒置,使用具体的例子来解释可能好些,网上千篇一律的大多...【详细内容】
2020-11-12  Tags: C#  点击:(33)  评论:(0)  加入收藏
▌简易百科推荐
取消宏定义定义变量的时候,不能够重复定义同名变量;同理,定义宏的时候,不可以重复定义同名的宏。例如:#define MAX 1000#define MAX 50此时,重复定义MAX宏,是不合法的代码。但是,我...【详细内容】
2021-07-13  峰哥linux编程学堂    Tags:预编译   点击:(2)  评论:(0)  加入收藏
函数参数传递指针变量在函数的定义中,函数的参数可以是各种变量,就包括指针变量。首先,我们来看看一个函数的定义:void func(char* p);该函数的名称叫做func,参数定义为 char* p...【详细内容】
2021-07-09  峰哥linux编程学堂    Tags:C语言指针   点击:(5)  评论:(0)  加入收藏
一、前言其实对 C/C++ 的应用来说,查看函数时间调用和内存消耗调用的有很多工具,valgrind 这个工具算是做得比较不错的一个。建议直接用 yum 安装,有的说可以安装更新的版本,像...【详细内容】
2021-07-09  编程Class  CSDN  Tags:valgrind   点击:(7)  评论:(0)  加入收藏
在实际的项目开发中,可能需要考虑代码的安全性或执行效率,需要将具体的功能实现隐藏,dll接口提供了很好的解决方案。dll接口不仅在C++的项目中可以直接调用,在C#开发的项目也同...【详细内容】
2021-07-09  积极的阳光i    Tags:C#   点击:(7)  评论:(0)  加入收藏
首先我们来介绍一下C++文章有点小长,因为介绍的很详细,请耐心阅读1.C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程...【详细内容】
2021-07-06  编程Class    Tags:C++   点击:(8)  评论:(0)  加入收藏
8 函数嵌套调用我们学习了函数的定义和使用,那么,函数在被调用之前,必须先进行定义或者声明。如下是一个程序测试例子: 程序运行结果如下: 可以看到,在main函数中调用了func函数。...【详细内容】
2021-07-03  峰哥linux编程学堂  今日头条  Tags:C语言   点击:(14)  评论:(0)  加入收藏
我是笑林新记,分享一下我使用C#的一些用法,希望对大家有帮助!欢迎关注:笑林新记Visual Studio版本:Enterprise 2015.net Framework版本:3.51Socket介绍 有粉丝私信说让讲一下局域...【详细内容】
2021-06-28  笑林新记说编程  今日头条  Tags: Socket   点击:(16)  评论:(0)  加入收藏
对于工程经验比较丰富的同学,并发应该也并不是陌生的概念了,但是每个人所理解的并发问题,却又往往并不统一,本文系统梳理了百度C++工程师在进行并发优化时所作的工作。...【详细内容】
2021-06-25  凯文神父  百度Geek说  Tags:并发优化   点击:(17)  评论:(0)  加入收藏
程序输入与输出当我们操作一个linux终端的时候,执行linux命令程序,可以看到命令的输出信息,或者要求输入数据。那么,这些操作就是linux命令程序与用户进行交互。程序与用户的交...【详细内容】
2021-06-23  峰哥linux编程学堂    Tags:C语言   点击:(23)  评论:(0)  加入收藏
1、C中内存分为四个区 栈:用来存放函数的形参和函数内的局部变量。由编译器分配空间,在函数执行完后由编译器自动释放。 堆:用来存放由动态分配函数(如malloc)分配的空间。是由程...【详细内容】
2021-06-23  冬日阳光Lee  公众号  Tags:C语言   点击:(15)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条