如何序列化HashSet以在检查器

时间:2018-04-27 03:29:03

标签: c# unity3d serialization

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>
{
}
  1. 如何让这个按预期工作(任意大小的字符串列表被(de)序列化为HashSet)?
  2. 另外,为什么OnBeforeSerialize每帧都被执行,即使检查员没有进行任何更改?
  3. 更多信息

    我已经弄明白了,因为当列表的大小发生变化时,默认情况下列表中的所有新元素都与前一个元素具有相同的值,因此所有元素都会被压缩到HashSet中的1个值。

    因此,虽然上面的问题2仍然存在,但问题1已经发展到要求为此做出解决方法,同时保持所需的HashSet功能。

1 个答案:

答案 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

相关信息:

  

如果对象的检查器在编辑器中打开,则调用每一帧