不要序列化字段但在检视面板中显示

5

假设我有一个这样的类:

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

我想使用BinaryFormatter序列化这个类。我无法序列化Transform组件,因此在序列化时需要忽略它,但是我仍然需要在检视面板中看到_transform字段。在这个例子中,只有_value字段应该被序列化。
如果我在_transform字段上使用[System.NonSerialized],它将不会在Unity检视面板中可见,如果我使用[SerializeFiled],我就无法使用BinaryFormatter序列化Transform。
这似乎有点像一个悖论...是否有可能做到这一点?

BinaryFormatter因其难以使用而臭名昭著,您能否使用JsonUtilty并将其保存为json格式? - Scott Chamberlain
@ScottChamberlain 我可以使用JsonUtility,但它会如何影响我的问题?我仍然不想序列化Transform字段。 - Powderek
你必须这样做,编辑器通过序列化对象并将其发送到编辑器来显示它的内容。您需要编写一个自定义编辑器组件来绕过此过程。另外,您从未说过您不想序列化该字段,您说您无法序列化它,就像您想这样做,但尝试时出现错误。我的JsonUtility建议是,也许类可以序列化它(我没有尝试过)。 - Scott Chamberlain
2个回答

3
我不建议使用场景对象或领域对象进行序列化。你将会在两种不同的序列化需求之间进行搏斗。
我建议将你的模型分为场景模型和持久化/序列化模型。
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类现在只有一个职责,您可以在任何字段上放置[SerializeFiled],因为这个对象不会用于任何其他序列化。您现在也可以使用任何您想要的序列化程序(JsonUtility、BinaryFormatter、JsonConvert、XmlSerializer等)。


1
我在我的答案和你的答案之间没有看到任何区别。基本上是将位置、旋转和缩放分离,然后将其保存为json的相同方法。关于这个答案,你应该知道以下几点:1.OP想在编辑器中看到_transform变量,而你没有包含它。2.JsonUtility无法序列化/反序列化你的答案中的类,因为使用了属性。 - Programmer
@程序员 显著的区别在于您使用单个对象来完成两个目的,这将始终存在问题。这已经在这里表现出来:“在将对象序列化为json之前调用updateValues()函数”。祝你记住每一次。属性是实现细节。您答案的问题在于违反了单一职责原则,使用一个对象来完成两个目的。当他添加LineRenderer并需要序列化位置时会发生什么?适当分离关注点后,他可以在Item._transform上添加[ SerializeField ]。 - Reasurria
1
这个概念很好,在大多数情况下可能是“正确”的方式,但并不是我希望得到的。我想要拥有一个用于检查器和序列化的单个对象。 - Powderek
@Powderek 嗯,在这种情况下,程序员的答案是正确的。 - Reasurria

2
我无法序列化Transform组件,因此在序列化时需要忽略它,但仍需要在检查器中看到_transform字段。您无法直接处理此问题,但有一个解决方法。像scott提到的那样,使用JsonUtilty。这并不能完全解决您的问题,但会防止在尝试反序列化JSON数据时出现错误,因为变量_transform。您只需要从Transform类中获取位置、旋转和缩放,因为它们都可以序列化,因为它们是Vector3或Quaternion类型,但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,您在序列化数据时将不会遇到任何问题。如果您打算保存它,请查看我制作的一个简单的包装器来处理所有这些。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接