---
title: "序列化与反序列化"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/unity-serialization-deserialization/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/05-游戏图形与运行时/Unity/序列化与反序列化.md"
content_hash: 1cfe3be54201d9d4b6795d56d6a1310fb9840f99885a03196659d98dedb12029
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
# 序列化与反序列化

> 创建时间：2020/6/9 14:33

Ref: <https://zhuanlan.zhihu.com/p/27990334>

## 概念

**序列化** 又称串行化，是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形式使自定义对象持久化，或者将这种对象从一个地方传输到另一个地方。

### 序列化

序列化是指把 **对象** 转换为 **字节序列** 的过程

对象序列化的最主要的用处就是在 **传递和保存对象** 的时候，保证对象的完整性和可传递性。序列化是把对象转换成有序字节流，以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了 **对象的状态以及相关的描述信息** 。序列化机制的核心作用就是对象状态的保存与重建。

### 反序列化

反序列化是指把 **字节序列** （有序字节流）恢复为 **对象** 的过程

客户端从文件中或网络上获得序列化后的对象字节流后，根据字节流中所保存的对象状态及描述信息，通过反序列化 **重建对象，恢复对象状态**

## 作用

  1. 永久性保存对象，保存对象的字节序列到本地文件或者数据库中；

  2. 通过序列化以字节流的形式使对象在网络中进行传递和接收；

  3. 通过序列化在进程间传递对象；

## Unity序列化

Unity的场景文件和预制体默认就是以二进制的文件保存在工程目录下。
在 **检视面板** 中可以看到的，就是被 **成功序列化了的参数** 。与序列化相关的常用的关键字如下，可以组合使用。

  * SerializeField : 表示变量可被序列化。众所周知，公有变量可以在检视面板中看到并编辑，而私有和保护变量不行。SerializeField与private，protected结合使用可以达到让脚本的变量在检视面板里可视化编辑，同时保持它的私有性的目的。

  * HideInInspector : 将原本显示在检视面板上的序列化值隐藏起来。

  * NonSerialized :通过此方法可以将一个公有变量不序列化并且不显示在检视面板中。

  * Serializable：用在类的前面，表示该类可被序列化。

**相关API**
SerializedObject: <https://docs.unity3d.com/ScriptReference/SerializedObject.html>
SerializedProperty: <https://docs.unity3d.com/ScriptReference/SerializedProperty.html>

> 注意：并非所有的公有变量都是可以被序列化的。其中const，static是静态的，属于类而非对象，无法序列化。链表和字典在内存中的存储是不连续的，也无法序列化。其中const，static，readonly的区别可参考文章：<https://www.cnblogs.com/suizhikuo/p/4739388.html>

## Demo

### 二进制方法（Binary Formatter）

```csharp
class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;
        dyn = dyn + 3;
        //obj = obj + 3; 报错

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

```

> 注意：二进制方法可以序列化私有变量，不能序列化被[NonSerialized ]修饰的变量且类需要被[Serializable ]标识。

### Xml序列化

XML(Extensible Markup Language, 可扩展标记语言), 标准通用标记语言(Standard Generalized Markup language, SGML)的子集。是一种用于标记电子文件使其具有结构性的标记语言。
提供统一的方法来描述和交换独立于应用程序或供应商的 **结构化数据** 。

```csharp
class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;
        dyn = dyn + 3;
        //obj = obj + 3; 报错

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

```

## 其他Unity数据存储方法

### ScriptableObject(自动序列化)

#### 使用方法

##### MenuItem

需要指定创建的目录和资源名称，如果资源已经存在，则不会创建新资源；

```csharp
class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;
        dyn = dyn + 3;
        //obj = obj + 3; 报错

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

```

##### CreateAssetMenu

可以在Assets下任意目录创建资源，而且可以创建多个资源；

```csharp
class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;
        dyn = dyn + 3;
        //obj = obj + 3; 报错

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

```

在Assets下创建一个可编程对象资源，设置好所需数据；如果需要在其它脚本中获取该数据，是需要声明一个该类型变量，然后为其赋值或加载该数据资源；然后，就像使用用一个类中的公有变量一样使用即可；

```csharp
class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;
        dyn = dyn + 3;
        //obj = obj + 3; 报错

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

```

### PlayerPrefs

Ref: <https://www.jianshu.com/p/579be3b8e1e3>
PlayerPrefs是Unity内置的一个静态类，可以用于存储一些简单的数据类型：int ,string ,float。可以用它来做成计分板这类需要可持续化存储的小地方。

#### PlayerPrefs数据存储在哪里?

1.在Mac OS X上存储在~/Library/PlayerPrefs文件夹，名为unity.[company name].[product name].plist,这里company和product名是在project Setting中设置的
2.在windows下，playerPrefs被存储在注册的HKCU\Software[company name][product name]键下，这里company和product名是在project setting中设置的。
3.在Android上，数据存储（持久化）在设备上。数据保存在SharedPreferences中。

#### PlayerPrefs有哪些方法？

分为五类：SetXXX , GetXXX , DeleteXXX, HasKey , Save.
传送门：<https://docs.unity3d.com/ScriptReference/PlayerPrefs.html>

  1. SetXXX : 是你要储存的数据类型，这里必须是一组键值对，第一个参数是Key,第二个参数是对应的Value。

  2. GetXXX：这里是获取数据的函数，只有一个参数Key,用来获取对应Key的Value.
3.HasKey: 这个可以用来做判断。比如有两组数据一组有XX这个Key,另一组没有XX这个Key,这个时候我们就可以对这两组数据进行差异化操作。

  3. DeleteXX:用于删除数据。

  4. Save:用于在突发退出程序时，保存数据以备恢复时使用，但是会导致程序间断所以不建议调用。
