【问题标题】:Do not serialize field but show in the inspector不要序列化字段但在检查器中显示
【发布时间】:2017-11-15 18:21:36
【问题描述】:

假设我有这样的课程:

[System.Serializable]
public class Item {
private Transform _transform;
private float _value;
}

我想用 BinaryFormatter 序列化这个类。我无法序列化 Transform 组件,因此我需要在序列化时忽略它,但我仍然需要此 _transform 字段在检查器中可见。在这个例子中,只有字段 _value 应该被序列化。

如果我在 _transform 字段上使用 [System.NonSerialized],它将在 Unity 检查器中不可见,如果我使用 [SerializeField] strong> 我不能用 BinaryFormatter 序列化 Transform。

好像有点悖论……有可能吗?

【问题讨论】:

  • BinaryFormatter 出了名的难用,你能用JsonUtilty 把它保存为json吗?
  • @ScottChamberlain 我可以使用 JsonUtility 但它将如何影响我的问题?我还是不想序列化 Transform 字段。
  • 好吧,你不得不这样做,编辑器通过序列化对象并将其发送给编辑器来显示它的东西。你需要编写一个custom editor 组件来绕过这个过程。你也从来没有说过你不想想要序列化这个字段,你说你不能序列化它,就像您想要的那样,但是您在尝试时遇到了错误。我的 JsonUtility 建议可能是该类可以序列化它(我没地方尝试)

标签: c# unity3d serialization


【解决方案1】:

我无法序列化 Transform 组件,所以我需要忽略它 序列化,但我仍然需要这个 _transform 字段在 检查员。

您不能这样做,但有一种解决方法。就像斯科特提到的那样,使用JsonUtilty。这不会完全解决您的问题,但会防止在您尝试反序列化 json 数据时出现错误,因为_transform 变量。

您只需要Transform 类中的位置、旋转和缩放,所有这些都可以序列化,因为它们是Vector3Quaternion,但Transform 不能序列化。所以你必须声明位置、旋转和缩放,并从_transform 变量中获取它们的值。然后,您可以序列化这 3 个值。

[System.Serializable]
public class Item
{
    //Will be ignored by JsonUtility but will be visible in the Editor
    [SerializeField]
    private Transform _transform;
    [SerializeField]
    private float _value;

    [SerializeField]
    private Vector3 position;
    [SerializeField]
    private Quaternion rotation;
    [SerializeField]
    private Vector3 scale;

    //Call before serializing
    public void updateValues()
    {
        position = _transform.position;
        rotation = _transform.rotation;
        scale = _transform.localScale;
    }
}

在将对象序列化为 json 之前调用 updateValues() 函数。

void Start()
{
    Item item = new Item();
    ...
    ...
    item.updateValues();
    string json = JsonUtility.ToJson(item);
    Debug.Log(json);
}

通过使用 json,您在序列化数据时不会遇到任何问题。如果您打算保存此内容,请查看我为处理所有这些而制作的简单 wrapper

【讨论】:

    【解决方案2】:

    我也不建议使用您的场景对象或域对象进行序列化。您将始终在两种不同的序列化要求之间进行斗争。

    我建议将您的模型分为场景模型和持久性/序列化模型。

    public class SerializableItemModel
    {
        public Vector3 position;
        public Quaternion rotation;
        public float _value;
    }
    

    然后有一个映射器可以在您的对象之间进行映射。

    public class ItemToModelMapper
    {
        public SerializableItemModel MapToModel(Item item)
        {
            var model = new SerializableItemModel
            {
                position = item.transform.position;
                rotation = item.transform.rotation;
                _value = item._value;
            };
            return model
        }
    
        public Item MapFromModel(SerializableItemModel model)
        {
            return new Item(model.position, model.rotation, model._value);
        }
    }
    

    如果你像这样分离你的对象,你将永远不必担心横切问题,比如序列化你的对象以保持持久性,并以某种方式在检查器中显示它等。如果你只想序列化 10% 的场景对象,那么你将其映射成一个小模型并对其进行序列化。

    当然,这比您可能希望编写的代码要多得多。如果您愿意,您可以将 Item 提供给 SerializableItemModel 构造函数并跳过映射层。

    public class SerializableItemModel
    {
        public Vector3 position;
        public Quaternion rotation;
        public float _value;
    
        public SerializableItemModel(Item item)
        {
             this.position = item.transform.position;
             this.rotation = item.transform.rotation;
             this._value = item.transform._value;
        }
    }
    

    现在您的代码在序列化时将如下所示:

    private ItemToModelMapper mapper;
    void Start()
    {
        Item item = new Item();
        ...
        ...
        // Serialize
        var serializationModel = this.mapper.MapToModel(item);
        string json = JsonUtility.ToJson(serializationModel );
    
        // Deserialize
        SerializableItemModel deserializedModel = JsonUtility.FromJson<SerializableItemModel>(json);
        Item loadedItem = this.mapper.MapFromModel(deserializedModel);
    }
    

    编辑:正如程序员所指出的,我从未解决过 Item 的检查器视图。因为 Item 类现在只有一个职责,所以欢迎您将 [SerializeField] 放在任何字段上,因为该对象不会用于任何其他序列化。您现在还可以使用任何您想要的序列化程序(JsonUtility、BinaryFormatter、JsonConvert、XmlSerializer 等)。

    【讨论】:

    • 我的回答中的内容与您的回答中的内容之间没有任何区别。基本上是分离位置、旋转和缩放,然后将其保存为 json。关于这个答案你应该知道的事情: 1.OP 想在编辑器中看到_transform 变量,而你把它忽略了。 2.JsonUtility 由于使用属性,无法序列化/反序列化答案中的类。
    • @Programmer 显着的区别是您将单个对象用于两个目的,这总是有问题的。这已经体现在“在将对象序列化为 json 之前调用 updateValues() 函数”。祝你好运,每次都记住这一点。属性是一个实现细节。您的答案的问题是违反单一责任,将一个对象用于两个目的。当他添加一个 LineRenderer 并且他需要序列化位置时会发生什么?正确分离关注点后,他可以在 Item._transform 上添加 [SerializeField]。
    • 这个概念很好,在大多数情况下它可能是“正确”的方式,但这不是我希望得到的。我确实想要一个用于检查器和序列化的对象。
    • @Powderek Ah 在那种情况下,程序员的答案是要走的路。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 2019-01-17
    • 2021-04-08
    相关资源
    最近更新 更多