为什么C#使用[System.Serializable]来保留实例?(Unity3D)

本文关键字:实例 保留 Unity3D 使用 System Serializable 为什么 | 更新日期: 2023-09-27 18:25:13

我想制作一个程序,如果它从检查器中获取TextAsset(它被放置在"ExampleEditor"中),它会制作一个自定义数据实例以使用blendshape动画。

起初,我不使用[System.Serializable].来创建自定义数据类

public class Matrix {
    public int row;
    public int col;
    public double[,] mat;
}

我的策略是获取一个TextAsset,解析TextAsset中的字符串,最后在"Example.cs"中为字段变量创建一个Matrix实例。我认为当它首先初始化和分配时,我可以在Example实例中使用该变量。但是,它没有工作,它引发了"NullReferenceException"。

所以我使用[System.Serializable]找到了解决方案。它确实有效。(我知道Unity3D不为他们的序列化方法提供多维数组。)

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class Matrix {
    [System.Serializable]
    public class mRow {
        public List<float> aRow = new List<float>();
    }
    [HideInInspector]
    [SerializeField]
    public int row;
    [HideInInspector]
    [SerializeField]
    public int col;
    //[HideInInspector]
    [SerializeField]
    public List<mRow> mat = new List<mRow>();
}

最后,我知道了解决办法,但我不知道为什么会出现这个问题。它与GC有关?

为什么C#使用[System.Serializable]来保留实例?(Unity3D)

你的问题不是很清楚,但我想知道你不明白的地方。

我的策略是获取一个TextAsset,解析来自TextAsset的字符串最后在"Example.cs"中为字段变量创建一个矩阵实例。

您没有解释您是如何做到这一点的(也许从自定义检查器调用解析函数?)。然而,不管您是如何从编辑器初始化字段的,如果字段不可序列化,则在从编辑器切换到播放模式时,它将为null

之所以会发生这种情况,是因为当进入播放模式时,Unity3D会序列化所有C#类,从而填充引擎的相对C++类。如果一个字段不是Unity可以序列化的类型的公共字段(或者甚至是用SerializeFieldAttribute标记的私有字段,总是Unity可以序列化的那种类型),Unity3D就不会序列化它

因此,当您切换到播放模式时,引用将为空。

换句话说,要从编辑器初始化的所有字段都必须是可序列化的,才能在播放模式下使用。

[SerializeField]
public List<mRow> mat = new List<mRow>();

上面的代码没有多大意义。如果您计划从检查器初始化一个可序列化字段,请不要通过代码对其进行初始化,否则最终可能会丢失引用。这种错误的一个例子:

[SerializeField]
private List<int> aList;
public void Start()
{
  aList = new List<int>();
} 

上面的代码会引起故障。如果您已经从检查器初始化了aList,它将被正确地序列化,但当您在播放模式e中切换时,会调用Start回调,aList将被重新初始化,并且您最终会引用一个空列表。

下面是一篇很好的博客文章,详细介绍了Unity3D如何处理对象的序列化。读一读!