Unity與C#的序列化與反序列化
序列化操作在我們的開發中使用的十分普遍,本文記錄了公司最近分享會上關於這部分的講解,希望能幫助大家對序列化有更系統的瞭解。
概念
序列化又稱序列化,是.NET執行時環境用來支援使用者定義型別的流化的機制。其目的是以某種儲存形式使自定義物件持久化,或者將這種物件從一個地方傳輸到另一個地方。
簡單來說就是將物件儲存到檔案中。如Unity的場景檔案和預製體預設就是以二進位制的檔案儲存在工程目錄下。
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; }
我們新建一個Test指令碼來驗證一下,輸入上述程式碼後觀察檢視面板:
然後將掛在指令碼的預製體用Sublime開啟觀察序列化部分:
耶,成功了!
此外,Unity還有類SerializedObject,常用於編輯器模式下的工具或匯入器中,修改資源或者Prefab的屬性。具體可參考官方文件:
https://docs.unity3d.com/ScriptReference/SerializedObject.html
注意:並非所有的公有變數都是可以被序列化的。其中const,static是靜態的,屬於類而非物件,無法序列化。連結串列和字典在記憶體中的儲存是不連續的,也無法序列化。其中const,static,readonly的區別可參考文章:
http://www.cnblogs.com/suizhikuo/p/4739388.html
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方法:可讀性強,但體積較大,可在無其他環境時使用。
總結
本文介紹了Unity中序列化相關的關鍵字及其區別和用法,C#中兩種序列化與反序列化的方法。
希望大家在日常開發中合理使用SerializeField,不用濫用Public。