Unity版本:2017.3.1f1
我正在尝试在 Unity 检查器中使用
HashSet
。具体来说,我需要一些 MonoBehaviour
s 来拥有 HashSet
字段,这些字段可以通过检查器修改它们的内容。
为了实现这个目标,我创建了一个具体的类,它是
HashSet
的子类,并在内部使用 List
进行(反)序列化,其方式与本指南中的字典非常相似:
但是我遇到了列表显示在检查器中的问题,但我不能在其中设置超过 1 个值。如果我将列表的大小设置为 2 或更大,它会立即设置回 1。
在尝试调试问题时,我发现
OnBeforeSerialize
(和notOnAfterDeserialize
)每帧都在执行,不断重置值。我不确定为什么将其设置为 1。
请注意,如果我在 1 个可用插槽中输入一个字符串,它不会被重置。因此,这种方法目前对于 0 或 1 个字符串的
HashSet
是“有效的”,但不会更多。此外,如果我使用 HashSet
字段而不是从它继承(就像上面链接中所做的那样),结果也不会改变。
这是一个最小的例子:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TEST : MonoBehaviour
{
public StringHashSet test;
}
[System.Serializable]
public class SerializableHashSet<T> : HashSet<T>, ISerializationCallbackReceiver
{
public List<T> values = new List<T> ();
public void OnBeforeSerialize ()
{
values.Clear ();
foreach (T val in this) {
values.Add (val);
}
}
public void OnAfterDeserialize ()
{
this.Clear ();
foreach (T val in values) {
this.Add (val);
}
}
}
[System.Serializable]
public class StringHashSet : SerializableHashSet<string>
{
}
HashSet
)?OnBeforeSerialize
每帧都被执行,即使没有在检查器中进行任何更改?更多信息
我发现这是因为当列表的大小发生变化时,默认情况下列表中的所有新元素都与前一个元素具有相同的值,因此在
HashSet
中都将被压缩为1值。
因此,虽然上面的问题 2 仍然存在,但问题 1 已经演变为寻求解决方法,同时保持所需的
HashSet
功能。
考虑到添加到问题中更多信息部分的发现,这是我解决这个问题的方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SerializableHashSet<T> : HashSet<T>, ISerializationCallbackReceiver
{
public List<T> values = new List<T> ();
public void OnBeforeSerialize ()
{
var cur = new HashSet<T> (values);
foreach (var val in this) {
if (!cur.Contains (val)) {
values.Add (val);
}
}
}
public void OnAfterDeserialize ()
{
this.Clear ();
foreach (var val in values) {
this.Add (val);
}
}
}
[System.Serializable]
public class StringHashSet : SerializableHashSet<string>
{
}
OnAfterDeserialize
是相同的。
OnBeforeSerialize
不再清除 values
列表。相反,它将新值从 HashSet
添加到 List
- 具体来说,存在于 HashSet
但不存在于 List
. 中的值
这允许在检查器中将新元素添加到列表时继续功能:重复和空白条目将正常工作,因为列表不会在任何时候被清除,只会添加到。
关于第二个问题,我找到了关于为什么
OnBeforeSerialize
如此频繁执行的信息:http://answers.unity.com/answers/796853/view.html
相关信息:
如果对象的检查器在编辑器中打开,则调用每一帧
我也需要在 Inspector 中有一个唯一的对象列表并且遇到了这个问题,这就是我解决它的方法:
宣布你的名单:
public List<T> list = new List<T>();
创建一个 OnValidate 方法:
private void OnValidate() {
int count = list.Count;
// remove duplicates
HashSet<T> uniqueList = new HashSet<T>(list);
list= uniqueList.ToList();
if (count > list.Count) {
list.Add(null);
}
}
希望对某人有所帮助。