实现字典的序列化

运行结果


点一下 “+” Button可以新增一个键值对,可以在 Inspector 面板设置键值的值,但不知道为什么 key 到输入框的距离不可控,只有将 inspector 面板变大才能完全看到,而且也没有禁用组件的勾选框了。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Script_04_11.cs 文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

// 继承 ISerializationCallbackReceiver 接口,实现 OnBeforeSerialize 和 OnAfterDeserialize
public class Script_04_11 : MonoBehaviour,ISerializationCallbackReceiver
{
[SerializeField]
// [HideInInspector] 加了SerializeField会显示在Inspector面板上,除非再加上一个 HideInInspector
private List<string> key_list = new List<string>();
[SerializeField]
private List<Sprite> value_list = new List<Sprite>();

//这里是 public 是因为下面要用 (target as Script04_11).m_spriteDic,这里最好也不要用 m_ 命名。
public Dictionary<string, Sprite> m_spriteDic = new Dictionary<string, Sprite>();

#region ISerializationCallbackReceiver implementation
// 序列化之前将字典里的内容传递到两个列表
void ISerializationCallbackReceiver.OnBeforeSerialize()
// public void OnBeforeSerialize()
{
key_list.Clear();
value_list.Clear();
foreach(KeyValuePair<string,Sprite> pair in m_spriteDic)
{
key_list.Add(pair.Key);
value_list.Add(pair.Value);
}
}

//反序列化之后将两个列表里的内容传递到词典里
void ISerializationCallbackReceiver.OnAfterDeserialize()
// public void OnAfterDeserialize()
{
m_spriteDic.Clear();
int size = key_list.Count;
if (size != value_list.Count)
{
Debug.LogError("反序列化时键值对数量不匹配");
return;
}
for(int i = 0; i < size; i++)
{
m_spriteDic[key_list[i]] = value_list[i];
}
}
#endregion
}

#if UNITY_EDITOR
[CustomEditor(typeof(Script_04_11))]
public class Script04_11_editor : Editor
{
public override void OnInspectorGUI()
{
// base.OnInspectorGUI();
serializedObject.Update();
SerializedProperty keyProperty = serializedObject.FindProperty("key_list");
SerializedProperty valueProperty = serializedObject.FindProperty("value_list");
GUILayout.BeginVertical();

// ? 是因为反序列化已经完成了所以不需要再次判断键值列表数量是否相等?
int size = keyProperty.arraySize;
for(int i = 0; i < size; i++)
{
GUILayout.BeginHorizontal();
//x 此时 keyProperty 是一个数组,要先获取每个 string 元素
//keyProperty.stringValue = EditorGUILayout.TextField("主键", keyProperty.GetArrayElementAtIndex(i).stringValue);
//valueProperty.objectReferenceValue = EditorGUILayout.ObjectField("图片",valueProperty.GetArrayElementAtIndex(i).objectReferenceValue, typeof(Sprite), false);

SerializedProperty key = keyProperty.GetArrayElementAtIndex(i);
SerializedProperty value = valueProperty.GetArrayElementAtIndex(i);
key.stringValue = EditorGUILayout.TextField("key", key.stringValue);
value.objectReferenceValue = EditorGUILayout.ObjectField("value", value.objectReferenceValue, typeof(Sprite), true);

GUILayout.EndHorizontal();
}
//GUILayout.EndVertical();
//GUILayout.BeginHorizontal();
if (GUILayout.Button("+"))
{
(target as Script_04_11).m_spriteDic[size.ToString()] = null;
}
//GUILayout.EndHorizontal();
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
#endif

感想

命名规范

雨松大大用的命名规范貌似不是Pascal(BackColor),Camel(backColor)或者匈牙利命名法(m_bFlag)。所以打算遇到一个总结一下:
私有成员变量: m_Keys
公有成员变量: spriteDic

代码规范

1、在关于编辑器的地方使用 #if UNITY_EDITOR and #endif ,比如在using UnityEditor; 和拓展编辑器的部分。
2、合理使用 #region xxxxx and #endregion,比如在接口的实现函数时。