Unity版本:2017.3.1f1
我尝试在Unity检查器中使用HashSet
。具体来说,我需要一些MonoBehaviour
来拥有HashSet
个字段,这些字段可以通过检查器修改其内容。
为了实现这个目标,我创建了一个子类HashSet
的具体类,并在内部使用List
进行(反)序列化,其方式与字典非常相似导:
但是,我遇到了一个问题,其中列表显示在检查器中,但我无法在其中设置多个值。如果我将列表的大小设置为2或更大,则会立即将其设置为1。
为了调试问题,我发现每帧都在执行OnBeforeSerialize
(和不 OnAfterDeserialize
),不断重置该值。我不确定为什么将它设置为1。
请注意,如果我在1个可用插槽中输入了一个字符串,则不会重置该字符串。所以这种方法目前是功能性的#34;对于HashSet
的0或1个字符串,但不是更多。此外,如果我使用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
功能。
答案 0 :(得分:0)
考虑到问题中更多信息部分添加的发现,我是如何解决这个问题的:
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
相关信息:
如果对象的检查器在编辑器中打开,则调用每一帧