序列化与反序列化
序列化与反序列化
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程,其逆过程一般称为反序列化。格式化器
使用命名空间System.Runtime.Serialization.Formatters.Binary
下的
BinaryFormatter binformatter = new BinaryFormatter();
得到一个格式化器实例。
序列化:Serialize(Stream, Object)
将对象实例序列化到给定的流。
反序列化:Deserialize(Stream)
指定的流反序列化为对象。
上下文信息: Context 获取或设置 StreamingContext 。C#中序列化过程会采用反射的方式获取对象的类型信息和数值等数据信息写入流(Stream)中,而反序列化过程则会重新申请内存空间一一获取存入流中的字段类型及数值等信息来创建一个新的实例。
当然序列化的方式不止一种,上面BinaryFormatter只是C#自身实现的序列化方式,但由于效率问题往往可能选择其它序列化技术来作为替代,常见的如protobuf-net会在后面写到。注意
- 被序列化的对象必须是可序列化的,通常使用特性System.SerializableAttribute也就是Serializable来标注。特性Serializable只能用于class、struct、enum、delegate,其中enum、delegate总是可以被序列化的,因此不必显式使用特性Serializable。
- 基类使用Serializable时,被派生类不会继承可序列化特性,如果被派生类使用Serializable,而基类没有使用该特性,则基类和派生类实例都不可被序列化。
- 序列化不会受可访问权限(无论是public还是private)影响,类中不想被序列化的字段可以使用特性NoSerializied标注,同一个类中可为多个字段使用。
- 由于被标记无法序列化的字段所存储的值的信息未被存入流中,因此在反序列化之后得到的实例中该字段的值会被赋予默认值(如int为0,bool为false等)。
序列化流程控制
在序列化与反序列化过程中,系统为我们提供了4个内置事件,这几个事件需要提供绑定的方法并给该方法标注对应的特性。如:
[OnSerialized]
void ReName(StreamingContext context) {
Debug.Log("serialized");
}
- 特性OnSerializing:序列化中
- 特性OnSerialized:序列化结束
- 特性OnDeserializing:反序列化中
- 特性OnDeserialized:反序列化结束
需要注意的是,每种特性只能标注一个方法,且返回类型必须为void,需要有一个StreamingContext类型参数。
StreamingContext
流的上下文StreamingContext是结构体类型,它有两个公共只读属性—State和Context。
Context:Object类型,表示一个上下文对象的引用,包含用户希望得到的任何上下文信息。
State: StreamingContextStates类型,用来说明要序列化和反序列化的对象的来源和目的地。
其中StreamingContextStates是个枚举类型:
public enum StreamingContextStates
{
CrossProcess = 1,
//将源或目标上下文指定为同一计算机上的不同进程
CrossMachine = 2,
//将源或目标上下文指定为不同的计算机
File = 4,
//将源或目标上下文指定为文件。 用户可以假设文件将比创建它们的进程持续更长时间,并且不会用使反序列化需要访问来自当前进程的任何数据的方式来序列化对象。
Persistence = 8,
//将源或目标上下文指定为持久化存储,其中可包括数据库、文件或其他后备存储。 用户可以假设持久化数据将比创建数据的进程持续更长时间,并且不会序列化对象以使反序列化需要访问来自当前进程的任何数据。
Remoting = 16,
//指定将数据远程连接到未知位置中的上下文。 用户无法假定这是否在同一台计算机上。
Other = 32,
//将序列化上下文指定为未知
Clone = 64,
//将对象图指定为正在克隆。 用户可以假定克隆的图形将继续存在于同一进程中,并且可以安全访问句柄或对非托管资源的其他引用。
CrossAppDomain = 128,
//将源或目标上下文指定为不同的应用程序域。
All = 255
//将序列化数据指定为可以传输到任何其他上下文或从任何其他上下文接收。
}
Unity中的序列化与反序列化
- Inspector中可视化的数值:由被观察对象反序列化得到。
- Prefab:以.prefab为后缀,资源与组件序列化后以文件形式存放,当需要时可反序列化得到实例。
其文件类型可自己设置:Edit—Project Settings—Editor–Asset Serialization
有二进制(Binary)和文本(Text)两种类型,可使用notepad打开查看,文件格式为YAML格式。
YAML的语法并不复杂,也常应用于编写配置文件,推荐阮一峰的这篇文章学习一下。 - Scene保存:以.unity为文件后缀,和Prefab类似也可以直接查看文本,同样是用YAML编写。
- Scene载入:读取序列化后的场景信息,在加载场景时进行反序列化。
编辑器代码重载:每次修改编辑器代码时会将旧的窗口数据序列化,加载新的代码或新的编辑器窗口时会将旧窗口的数据反序列化供新窗口使用。
在Unity中序列化需要注意的:
- 被序列化的对象引用或字段不能是null,否则它会创建一个新的该类型实例。一旦引用类型是自身类则可能进入不断循环。
- 被序列化字段不能是static、const、readonly类型。
- 如C#中序列化,需要是可序列化的类型(几个基本类型、带Serializable特性、继承自UnityEngine.Object等)
参考资料:
1.《Unity3d脚本编程》—陈嘉栋 著