Как сериализовать HashSet для использования в инспекторе - PullRequest
0 голосов
/ 27 апреля 2018

версия Unity: 2017.3.1f1

Я пытаюсь работать с HashSet в инспекторе Unity. В частности, мне нужно, чтобы MonoBehaviour s имел поля HashSet, содержимое которых можно изменять с помощью инспектора.

Для достижения этой цели я создал конкретный класс, который подклассов HashSet, и использует List внутренне для (де) сериализации, очень похоже на Словарь в этом руководстве:

Однако я сталкиваюсь с проблемой, когда список отображается в инспекторе, но я не могу установить более 1 значения в нем. Если я установлю размер списка на 2 или больше, он сразу же вернется к 1.

В попытке отладить проблему, я обнаружил, что OnBeforeSerializeне OnAfterDeserialize) выполнялся каждый кадр, непрерывно сбрасывая значение. Я не уверен, почему он устанавливал его на 1, хотя.

Обратите внимание, что если я введу строку в 1 доступный слот, она не будет сброшена. Таким образом, этот подход в настоящее время «функционален» для 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 выполняется каждый кадр, даже если в инспекторе не производится никаких изменений?

Дополнительная информация


Я понял, что это потому, что при изменении размера списка все новые элементы в списке по умолчанию имеют то же значение, что и предыдущий элемент, поэтому все они будут сжаты до 1 значения в HashSet.

Таким образом, в то время как вопрос 2 остается сверху, вопрос 1 эволюционировал, чтобы попросить обойти это, сохраняя при этом желаемую функциональность HashSet.

1 Ответ

0 голосов
/ 28 апреля 2018

Вот как я решил эту проблему, учитывая открытия, добавленные в раздел Дополнительная информация в вопросе:

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

Соответствующая информация:

Вызывается каждый кадр, если в редакторе открыт инспектор для объекта

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...