序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形式使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。简单来说就是将对象保存到文件中。如Unity的场景文件和预制体默认就是以二进制的文件保存在工程目录下。
序列化可以用于跨平台。实际上就是把一段数据翻译成(序列化)比较底层的语言(如汇编、机器语言),而基于这个底层语言再可以翻译(反序列化)成多种上一层的语言。
Unity会自动序列化所有你自己写的脚本组件(Scriptable Object), 重载新的程序集,并且重新创建你的脚本组件。简单的说,序列化后,数据就可以被保存了。Unity序列化过程不走.NET的方法,而是Unity内部的方法。
可序列类型
所有继承至UnityEngine.Object的类,如MonoBehaviour。
所有基本数据类型,如int、string等。
一些内置类型,如Vector3、Quaternion,、Matrix4x4、Color、Rect、 LayerMask等。
一列可序列化类型的列表。
枚举类型。
结构类型。
Unity可以序列化的有:
- 可序列化类型中公有非静态字段。
- 非公有非静态,但是带[SerializeField] 特性的字段。
Unity不可以序列化的有:
- 静态字段
- 属性(Property)
Unity序列化
在Unity中,在检视面板中可以看到的,就是被成功序列化了的参数。与序列化相关的常用的关键字有SerializeField,HideInInspector,NonSerialized,Serializable并可以组合使用。
SerializeField : 表示变量可被序列化。众所周知,公有变量可以在检视面板中看到并编辑,而私有和保护变量不行。SerializeField与private,protected结合使用可以达到让脚本的变量在检视面板里可视化编辑,同时保持它的私有性的目的。
HideInInspector : 将原本显示在检视面板上的序列化值隐藏起来。
NonSerialized :通过此方法可以将一个公有变量不序列化并且不显示在检视面板中。
Serializable:用在类的前面,表示该类可被序列化。
示例:
public class Test :Monobehavior
{
public int a; //序列化,显示
private int b; //不序列化,不显示
[SerializeField ] int c; //序列化,显示
[HideInInspector] public int d; //序列化,不显示
[NonSerialized ] public int e; //不序列化,不显示
public Test2 test2; //序列化,显示(可序列化的部分)
}
[Serializable ]
public class Test2
{
public int aa;
private int bb;
}
注意:并非所有的公有变量都是可以被序列化的。其中const,static是静态的,属于类而非对象,无法序列化。链表和字典在内存中的存储是不连续的,也无法序列化。
C#序列化
简单介绍两种常用的C#序列化操作(二进制方法和XML方法)
首先我们先定义一个可被序列化的类DemoClass
[Serializable]
public class DemoClass
{
public int _id;
public string _myName;
public DemoClass(int id, string myName)
{
_id = id;
_myName = myName;
}
public DemoClass()
{
}
public void Output()
{
Debug.LogError(_id);
Debug.LogError(_myName);
}
}
它包含两个公有变量id和name,一个含参的构造函数和一个默认构造函数(二进制不需要,XML必须), 一个用于显示的输出函数
二进制方法(Binary Formatter)
序列化:新建或打开一个二进制文件,通过二进制格式器将对象demo写入该文件中。
void WriteTest()
{
DemoClass demo = new DemoClass (100, "RCD");
FileStream fs = new FileStream ("demo.bin", FileMode.OpenOrCreate);
BinaryFormatter bf = new BinaryFormatter ();
bf.Serialize (fs, demo);
fs.Close ();
Debug.LogError ("write done");
}
反序列化:打开待反序列化的二进制文件,通过二进制格式器将文件解析成对象demo,并输出到控制台。
void ReadTest()
{
FileStream fs = new FileStream("demo.bin", FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
DemoClass demo = bf.Deserialize(fs) as DemoClass;
fs.Close();
demo.Output();
}
注意:二进制方法可以序列化私有变量,不能序列化被[NonSerialized ]修饰的变量且类需要被[Serializable ]标识。
XML方法(XML Serializer)
序列化与反序列化与二进制方法十分类似。
序列化:
void WriteTest()
{
DemoClass demo = new DemoClass(100, "RCD");
FileStream fs = new FileStream("demo.xml", FileMode.OpenOrCreate);
XmlSerializer xml = new XmlSerializer(typeof(DemoClass));
xml.Serialize(fs, demo);
fs.Close();
Debug.LogError("write done");
}
反序列化:
void ReadTest()
{
FileStream fs = new FileStream("demo.xml", FileMode.Open);
XmlSerializer bf = new XmlSerializer(typeof(DemoClass));
DemoClass demo = bf.Deserialize(fs) as DemoClass;
fs.Close();
demo.Output();
}
注意:XML方法中类不需要[Serializable]标识,不能序列化私有变量,[NonSerialized]这个标识在该方法中无效。
区别:
二进制方法:性能好,体积小。
XML方法:可读性强,但体积较大,可在无其他环境时使用。