首页 > 解决方案 > 在 Unity C# 中序列化 ObservableCollection 类 ObservableList

问题描述

由于目前ObservableCollection尚不支持在 Unity 中对 C# 进行序列化,因此我使用了一个脚本,该脚本扩展List<>并创建了一个名为 Serializable 的类ObservableList,如本统一论坛答案ObservableList中所述。以下是相同的代码:

[Serializable]
 public class ObservedList<T> : List<T>
 {
     public event Action<int> Changed = delegate { };
     public event Action Updated = delegate { };
     public new void Add(T item)
     {
         base.Add(item);
         Updated();
     }
     public new void Remove(T item)
     {
         base.Remove(item);
         Updated();
     }
     public new void AddRange(IEnumerable<T> collection)
     {
         base.AddRange(collection);
         Updated();
     }
     public new void RemoveRange(int index, int count)
     {
         base.RemoveRange(index, count);
         Updated();
     }
     public new void Clear()
     {
         base.Clear();
         Updated();
     }
     public new void Insert(int index, T item)
     {
         base.Insert(index, item);
         Updated();
     }
     public new void InsertRange(int index, IEnumerable<T> collection)
     {
         base.InsertRange(index, collection);
         Updated();
     }
     public new void RemoveAll(Predicate<T> match)
     {
         base.RemoveAll(match);
         Updated();
     }


     public new T this[int index]
     {
         get
         {
             return base[index];
         }
         set
         {
             base[index] = value;
             Changed(index);
         }
     }
 }

它仍然没有被序列化,我在 Unity 编辑器中看不到它。任何帮助将不胜感激!

编辑#1

预期用例:

public class Initialize : MonoBehaviour
{
    public ObservedList<int> percentageSlider = new ObservedList<int>();
    
    void Start()
    {
        percentageSlider.Changed += ValueUpdateHandler;
    }
    
    void Update()
    {
    }
    
    private void ValueUpdateHandler(int index)
    {
        // Some index specific action
        Debug.Log($"{index} was updated");
    }
}

我将此脚本作为组件附加到 GameObject 上,以便我可以输入size此列表的 ,玩弄这些值(就像我可以使用 一样)并执行一些操作,这些操作只有在更新List内部的某些值时才会触发。ObservableList

我想看的

督察

我所看到的

检查员2

标签: c#unity3d

解决方案


  1. 如果您希望对操作进行序列化,则必须使用 UnityEvents(它与 Unity 的序列化事件系统挂钩)。

  2. 确保在要序列化的所有类型之前使用 [SerializedField] 属性。

  3. 主要问题可能源于继承,它不能很好地与 Unity 的序列化系统配合使用。一般来说,我永远不会从 List 继承(这里有一些原因)相反,我会让你的 observable 类型成为 List 的包装器,并带有一些附加功能(List 将是 Observable 中的成员)。

编辑 1

添加了经过测试的代码示例。ObservedList<T> 不是继承,而是充当 List<T> 的包装器。您将能够订阅 Changed 和 Updated 事件,但它们没有被序列化。如果您想访问任何其他列表功能,您只需在 ObservedList<t> 类中添加一个公共方法,该方法充当其包装器。如果您有任何其他问题,请告诉我。

[Serializable]
public class ObservedList<T>
{
    public event Action<int> Changed;
    public event Action Updated;
    [SerializeField] private List<T> _value;
    
    public T this[int index]
    {
        get
        {
            return _value[index];
        }
        set
        {
            //you might want to add a check here to only call changed
            //if _value[index] != value
            _value[index] = value;
            Changed?.Invoke(index);
        }
    }
    
    public void Add(T item)
    {
        _value.Add(item);
        Updated?.Invoke();
    }
    public void Remove(T item)
    {
        _value.Remove(item);
        Updated?.Invoke();
    }
    public void AddRange(IEnumerable<T> collection)
    {
        _value.AddRange(collection);
        Updated?.Invoke();
    }
    public void RemoveRange(int index, int count)
    {
        _value.RemoveRange(index, count);
        Updated?.Invoke();
    }
    public void Clear()
    {
        _value.Clear();
        Updated?.Invoke();
    }
    public void Insert(int index, T item)
    {
        _value.Insert(index, item);
        Updated?.Invoke();
    }
    public void InsertRange(int index, IEnumerable<T> collection)
    {
        _value.InsertRange(index, collection);
        Updated?.Invoke();
    }
    public void RemoveAll(Predicate<T> match)
    {
        _value.RemoveAll(match);
        Updated?.Invoke();
    }
}

推荐阅读