C#_Serialize和Deserialize
一、概念
序列化是通过将对象转换为字节流,从而存储对象或将对象传输到内存、数据库或文件的过程。主要用途是保存对象的状态,包括对象的数据,以便能够在需要时重建对象。反向过程称为反序列化。
如上图所示,对象object被序列化为字节流,其中不仅包括数据、还包括对象类型的相关信息,如版本、区域性和程序集名称。然后可以将此流中的内容存储到数据库中、文件或内存中。
二、序列化的三种类型
- 二进制。就是字节流可以存储在本地文件中或者socket网络流等
- XML。存储为XML文件
- Json。存储为Json文件
在这里我们重点介绍一下二进制类型的相关问题。XML和Json很类似,后期会侧重介绍Json。
三、二进制序列化后的字节流中到底是什么?
要想知道这个问题,我们就写一个小Demo。将一个对象进行二进制序列后存储为文件。
public class Person
{
public string Name { get; set; }
public uint Age { get; set; }
public UInt16[] Data { get; set; }
}
首先自定义一个类,但是这样的类时不可以直接被序列化的,必须要在类上加一个[Serialize]特性。如果类中还有其他自定义类型的字段,那么该类型也需要加上[Serialize]特性。
[Serializable]
public class Person
{
public string Name { get; set; }
private uint age;
public uint Age
{
get { return age; }
set { age = value; }
}
public UInt16[] Data { get; set; }
}
因为默认情况下,会序列化类中的所有字段,如果需要忽视不需要序列化也需要加上[NonSerialized]特性。注意,这个特性只能加在字段上。
[Serializable]
public class Person
{
public string Name { get; set; }
[NonSerialized]
private uint age;
public uint Age
{
get { return age; }
set { age = value; }
}
public UInt16[] Data { get; set; }
}
接下来进行序列化也反序列化:
Person p = new Person
{
Name = "zhanghanyun",
Age = 0x18,
Data = new UInt16[] { 0x11, 0x22, 0x33, 0x44, 0x55 },
};
using (FileStream fs = new FileStream(@"Person.dat",FileMode.Create))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, p);
}
using (FileStream fs = new FileStream(@"Person.dat",FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
Person p1 = (Person)formatter.Deserialize(fs);
}
代码也挺简单的,主要用到了BinaryFormatter类,它有Serialize()方法和Deserialize()方法,这两个方法都需要一个Stream类型,我们示例中使用的FileStream因为需要存储本地文件,也可以使用MemoryStream。
接下来我们看看那个二进制文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oMJ2vxYs-1609411109383)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20201231160135527.png)]
在这个文件中,我们果然看到了我们定义的Name,还有Data。Age由于被ignore了,所以在文件中找不到。但除了这些字段,还有版本、区域性和程序集名称等信息保存了。
所以,如果我们直接将对象序列化然后再通过网络流传送(用户数据域一般还会自定义协议)给其他进程,是非常不合适的。因为自定义协议可能只需要我们的字段字节流。
四、字节流的顺序和类中字段的顺序有关系吗?
接着上述的例子,我们将Name属性放在最后面再试一试。
[Serializable]
public class Person
{
[NonSerialized]
private uint age;
public uint Age
{
get { return age; }
set { age = value; }
}
public UInt16[] Data { get; set; }
public string Name { get; set; }
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2SOlYDZ-1609411109386)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20201231161203021.png)]
好像只有红框中的内容发送了变化,后面的字段字节流的顺序并没有发送变化。所以,字段字节流的顺序不一定与类中字段的顺序一致。
但是这个顺序到底是由什么决定的?俺也不知道。。。。不知道有没有大佬告知一下
五、自定义序列化
具体有什么实际的用处,俺还是不知道。。。
大佬告知一下
六、可以只序列化对象中的字段吗?不需要额外信息
俺目前不知道。但是如果只需要对象中的成员组成的字节流,应该不能使用序列化。
我想到了一些办法。。。见链接