Unity的数据存储,本地类 PlayerPrefs, Inspector,以及Prefab等都使用了序列化与反序列化的知识.
循序渐进,让我们一步步了解Unity中的序列化和反序列化的知识;
流与格式化器
序列化: 将对象转换为字节流.
反序列化: 将字节流转换为对象.
直接讲概念太抽象,我们先来看代码;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
public class Test : MonoBehaviour
{
private void Start()
{
Hero hero_ins = new Hero();
hero_ins.id = 100;
hero_ins.attack = 99f;
hero_ins.defence = 99f;
hero_ins.name = "Calabash";
Stream st = FormatInstanceToMemory(hero_ins);
st.Position = 0;
hero_ins = null;
hero_ins = MemoryToInstance(st) as Hero;
Debug.Log(hero_ins.id.ToString());
Debug.Log(hero_ins.attack.ToString());
Debug.Log(hero_ins.defence.ToString());
Debug.Log(hero_ins.name);
}
//序列化 把实例对象写入流中
private static MemoryStream FormatInstanceToMemory(object instance)
{
//创建一个流
MemoryStream ms = new MemoryStream();
//创建格式化器
BinaryFormatter bf = new BinaryFormatter();
//序列化为二进制流
bf.Serialize(ms, instance);
return ms;
}
//反序列化, 从流中读出实例对象
private static object MemoryToInstance(Stream st)
{
//创建格式化器
BinaryFormatter bf = new BinaryFormatter();
//把二进制流反序列化为指定的对象
return bf.Deserialize(st);
}
}
关于Hero类的定义如下:
[Serializable] //注意这个关键字
public class Hero
{
public int id;
public float attack;
public float defence;
public string name;
}
代码中的注释已经写得很清楚了,通过代码我们要解释三个概念;
流(Stream): Unity中的二进制数据流,有 MemoryStream, FileStream 等子类来处理不同场景的数据流,但我们这里不讨论每种流的用法,只需要让大家理解 Stream提供了一个用来容纳经过序列化之后的字节块的容器
更多的Stream知识可以查阅这里: Unity的Stream流
格式化器: 使用序列化和反序列的工具,代码中只是使用到了 BinaryFormatter 这种格式化器,其实还有 SoapFormatter (需要导入对应的.dll文件),需要注意的是进行序列化和反序列的操作必须是相同的格式化器,否则可能会抛出System.Runtime.Serialization.SerializationException异常.
[Serializable]特性: 默认自定义的类型是无法被序列化的,需要使用 [Serializable] 特性来实现序列化与反序列化,关于此特性更多的内容见下节;
通过上面的示例,我们往流中写入了一个对象,那么可以写入两个,甚至多个不同的对象么?答案是肯定的,我们还是用代码测试一下;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
public class Test : MonoBehaviour
{
private void Start()
{
Hero hero_ins = new Hero();
hero_ins.id = 100;
hero_ins.attack = 99f;
hero_ins.defence = 99f;
hero_ins.name = "Ca