Unity:自 5.0 版以来的序列化问题(Parent/Children 关系)

Unity: Issue with serialization since version 5.0 (Parent/Children relationship)

当我使用旧版本的 Unity 时没有问题,但自从升级后我不断收到所有 classes 的错误,其中 class 包含其类型的 children:在 'Formation' 处超出了序列化深度限制。在您的一个或多个序列化 class 中可能存在 object 合成周期。

我有一个 class 这样的:

[Serializable]
public class Formation {
    public List<Formation> Formations;
}

写了一些循环,但是为什么没有无限循环的时候会有问题,因为每个child实例都要初始化,所以如果用户想做无限循环他就去做,但只能通过显式初始化 children...

这是什么错误吗?我已经在论坛上阅读了一些建议删除 children 的帖子,但我不明白为什么会出现这种行为。

顺便说一下这个class我上次写的连序列化都没有,连列表实例都没有

嗯,老实说,这很明显...这是因为执行序列化时会发生什么。跟我走吧:你有一个 class Formation,其中包含 Formation 的集合。这些都是 Formation 类型的,所以它们每个都有一个集合。以此类推...循环几乎是无限的。

Formation
     List
           Formation
                 List
                      Formation
                                List
                                      ....

最简单的解决方法是将集合移动到更有意义的地方 class(在 Formation 之外)。我不认为 Formation 应该有一个包含更多 Formation 的列表...

我有类似的循环序列化问题。我通过显式使父实例不可序列化来解决它。

例如

[Serializable]
class A
{
    [SerializeField]
    B _bInstance;
    ...
}
...
[Serializable]
class B
{
    A _aInstance;
    ...
}

变成

[Serializable]
class A
{
    [SerializeField]
    B _bInstance;
    ...
}
...
[Serializable]
class B
{
    [NonSerialized]
    A _aInstance;
    ...
}

希望这会有所帮助。

基本上这个问题可以通过将所有可以具有相同类型子对象的对象存储在一个容器中来解决,该容器将在序列化时处理子-父关系。 这是一个例子:

using System;
using System.Runtime.Serialization;
using System.Collections.Generic;

[Serializable]
public class MyObject
{
    [NonSerializeble]
    public MyObject child;
}

//this is the class that you are going to serialize
[Serializable]
public class ObjectsContrainer
{
    private List<MyObject> allObjects;
    private List<serializationInfo> serializationInfos;

    //save info about the children in a way that we dont get any cycles
    [OnSerializing]
    private void OnSerializingStarted(StreamingContext context)
    {
        serializationInfos = new List<serializationInfo>();
        foreach (var obj in allObjects)
        {
            serializationInfo info = new serializationInfo {
                parentIndex = allObjects.FindIndex(x => x == obj),
                childIndex =  allObjects.FindIndex(x => x == obj.child)
            serializationInfos.Add(info);
        }
    }

    //restore info about the children
    [OnDeserialized]
    private void OnDeserialized(object o)
    {
        //restore connections
        foreach (var info in serializationInfos)
        {
            var parent = allObjects[info.parentIndex];
            parent.child = allObjects[info.childIndex];
        }
    }

    [Serializable]
    private struct serializationInfo
    {
        public int childIndex;
        public int parentIndex;
    }
}