c# - 有没有办法将引用的 MonoBehaviours 序列化为 JSON?

标签 c# .net json unity3d serialization

假设我有一个名为 ObjectA 的对象,它包含两个对象:ObjectsBObjectC

[System.Serializable]
public ClassA
{
    public ClassB classB;
    public ClassC classC;

    public ClassA()
    {
        classB = new ClassB();
        classC = new ClassC();
    }
}

[System.Serializable]
public ClassB
{
    //Some fields.
}

[System.Serializable]
public ClassC
{
    //Some fields.
}

如果我将 ObjectA 序列化为 JSON,ObjectBObjectC 不会被序列化。这是我将 ObjectA 序列化为 JSON 后得到的:
{"_instanceB":{"instanceID":10480},"_instanceC":{"instanceID":10230}}
我需要将所有这些对象序列化为一个文件并将其保存在本地硬盘上,以便以后能够恢复它们的状态。我该怎么做?
我是否应该从 ClassA 中检索 ClassBClassC 然后序列化并分别保存它们?像这样:

public void Save()
{
    //Get instances of ClassB and ClassC.
    ClassB classB = classA.GetClassB;
    ClassC classC = classA.GetClassC;

    //Generate different JSON for each class.
    string classA_JSON = JsonUtility.ToJson(classA);
    string classB_JSON = JsonUtility.ToJson(classB);
    string classC_JSON = JsonUtility.ToJson(classC);

    //Paths for saving locally.
    string pathForClassA = Path.Combine("C:\\", "classA.json");
    string pathForClassB = Path.Combine("C:\\", "classB.json");
    string pathForClassC = Path.Combine("C:\\", "classC.json");

    File.WriteAllText(pathForClassA, classA_JSON);
    File.WriteAllText(pathForClassB, classB_JSON);
    File.WriteAllText(pathForClassC, classC_JSON);
}

看起来很难看,它会为每个嵌套类生成一个新的 JSON 文件。我能否以某种方式将 ClassA 及其嵌套类序列化为一个 JSON 文件?

P.S. 这是一个 Unity 项目,ClassAClassBClassC 派生自 MonoBehaviour 。由于 BinaryFormatter 不支持 MonoBehaviour 我无法使用它。唯一留给我的就是将它序列化为 JSON。

最佳答案

Can I somehow serialize ClassA including its nested classes into one JSON file?

是的,你可以,但它需要一些工作:

您可以为 ClassBClassC 使用 [Serializable] 表示类,并使用 ISerializationCallbackReceiver interface用于在 ClassA

中填充和使用它们

类似的东西

public class ClassB : MonoBehaviour
{
    [SerializeField] private float example1;
    [SerializeField] private string example2;
    // etc.

    public void SetUp(SerializableClassB values)
    {
        // set all values
        this.example1 = values.example1;
        this.example2 = values.example2;
        // etc.
    }

    public SerializableClassB GetSerializable()
    {
        var output = new SerializableClassB();

        output.example1 = this.example1;
        output.example2 = this.example2;
        // etc.

        return output;
    }
}

[Serializable]
public class SerializableClassB
{
    public float example1;
    public string example2;
    // etc
}

对于 ClassC 也是如此

public class ClassC : MonoBehaviour
{
    [SerializeField] private float example3;
    [SerializeField] private string example4;
    // etc.

    public void SetUp(SerializableClassC values)
    {
        // set all values
        example3 = values.example3;
        example4 = values.example4;
        // etc.
    }

    public SerializableClassC GetSerializable()
    {
        var output = new SerializableClassC();

        output.example3 = example3;
        output.example4 = example4;
        // etc.

        return output;
    }
}

[Serializable]
public class SerializableClassC
{
    public float example3;
    public string example4;
    // etc
}

然后在 ClassA 中你可以做

public class ClassA : MonoBehaviour, ISerializationCallbackReceiver
{
    public ClassB _classB;
    public ClassC _classC;

    [SerializeField] private SerializableClassB _serializableClassB;
    [SerializeField] private SerializableClassC _serializeableClassC;


    public void OnBeforeSerialize()
    {
        // before writing to a Json get the information from the MonoBehaviours into the normal classes
        if(_classB) _serializableClassB = _classB.GetSerializable();
        if(_classC) _serializeableClassC = _classC.GetSerializable();

    }

    public void OnAfterDeserialize()
    {
        // after deserializing write the infromation from the normal classes into the MonoBehaviours
        if(_classB) _classB.SetUp(_serializableClassB);
        if(_classC) _classC.SetUp(_serializeableClassC);
    }
}

第二个巨大的优势(副作用)是现在您还可以直接在 ClassA 上控制 _classB_classC 的值> 实例。这样您就可以在集中式管理器类中修改 MonoBehaviour 值。

enter image description here

序列化为json后使用

private void Start()
{
    File.WriteAllText(Path.Combine(Application.streamingAssetsPath, "Test.txt"), JsonUtility.ToJson(this));
    AssetDatabase.Refresh();
}

你现在得到

{
    "_classB":{"instanceID":-6766},"_classC":{"instanceID":-6826},
    "_serializableClassB": {
            "example1":23.0,
            "example2":"54ththfghg"
    },
    "_serializeableClassC": {
            "example3":67.0,
            "example4":"567gffhgfhgf"
    }
}

比起我把它改成的例子

{
    "_classB":{"instanceID":-6766},"_classC":{"instanceID":-6826},
    "_serializableClassB": {
            "example1":47,
            "example2":"Hello"
    },
    "_serializeableClassC": {
            "example3":32.123,
            "example4":"World!"
    }
}

并使用 json 开始反序列化

private void Start()
{
    JsonUtility.FromJsonOverwrite(File.ReadAllText(Path.Combine(Application.streamingAssetsPath, "Test.txt")), this);
}

enter image description here

关于c# - 有没有办法将引用的 MonoBehaviours 序列化为 JSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56569824/

相关文章:

java - 如何在 blogger api 中按标签获取博客文章

.net - CefSharp 不能在 WIndows 7 中运行

python - 如何使用多个字典转换字符串,以便 json.load 可以解析它?

c# - 仅对 DbContext 中的一个查询使用选项 IsolationLevel.ReadUncommited

c# - 标记为内容的 Windows Phone 8 文件的位置

.net - 什么决定了 EF Code First 的 SQL Azure 数据库版本和大小?

c# - 在 XAML ResourceDictionary 中绑定(bind)

javascript - 我可以在不使用 AJAX 的情况下发布 JSON 吗?

c# - 为什么 System.Exception.ToString 不为内部异常调用虚拟 ToString?

c# - 没有 Controller 的 Web API MVC 模型验证