使用ISerializationCallbackReceiver解决HashSet/Dictionary无法序列化的问题

自定义数据类被标记为[Serializable]后, 像 HashSet<T> / Dictionary<T> 类型的数据依然无法被Unity自动序列化。一种办法是内部再存一个数据列表(一般是List<T>类型),序列化之前先把数据倒腾到List<T>中, 在运行时加载后再执行自己写的 "Init()" 之类的函数将数据从List<T>中倒腾到 HashSet<T>中。实际上,对于这种情况,Unity已经提供了一个处理方式: ISerializationCallbackReceiver。自定义的数据类只需要实现这个接口,Unity自己就会在序列化/发序列化时自动执行对应操作。

该接口很简单,在Unity中定义如下:

    [RequiredByNativeCode]
    public interface ISerializationCallbackReceiver
    {
        //
        // 摘要:
        //     Implement this method to receive a callback after Unity deserializes your object. //将在Unity反序列化你的对象后被执行。
        [RequiredByNativeCode]
        void OnAfterDeserialize();
        //
        // 摘要:
        //     Implement this method to receive a callback before Unity serializes your object. //将在Unity序列化你的对象之前被执行。
        [RequiredByNativeCode]
        void OnBeforeSerialize();
    }

当然,并非只有集合类才能这样操作。以下是一段简单的示例代码:

 1 using System.Collections.Generic;
 2 using UnityEngine;
 3 using System;
 4 
 5 namespace THP.ExampleCode.SerializationCallback
 6 {
 7     [Serializable] 9     public class Items : ISerializationCallbackReceiver
10     {
11         /// <summary>
12         /// dictionary of items. key: Item.Id value: Item
13         /// </summary>
14         public Dictionary<int, Item> ItemDict = new Dictionary<int, Item>();
15         [SerializeField]
16         List<Item> itemList;
17 
18         public void OnAfterDeserialize()
19         {
20             foreach (var item in itemList)
21             {
22                 ItemDict.Add(item.Id, item);
23             }
24         }
25 
26         /// <summary>
27         /// 将在序列化之前执行。
28         /// </summary>
29         public void OnBeforeSerialize()
30         {
31             itemList = new List<Item>();
32             foreach (var kv in ItemDict)
33             {
34                 itemList.Add(kv.Value);
35             }
36         }
37     }
38 
39     [Serializable]
40     public class Item : ISerializationCallbackReceiver
41     {
42         [NonSerialized]
43         public int Id;
44         [NonSerialized]
45         public string Name;
46         // ... other infos
47         [SerializeField]
48         private byte[] compressedByteArray;
49 
50         public void OnAfterDeserialize()
51         {
52             CompressToolAtSomewhere.DecompressItemInfo(compressedByteArray, this);
53         }
54 
55         public void OnBeforeSerialize()
56         {
57             compressedByteArray = CompressToolAtSomewhere.CompressItemInfo(this);
58         }
59     }
60 }

 

posted on 2019-02-02 11:50  tang_huipang  阅读(1263)  评论(0编辑  收藏  举报