不要序列化字段,但在检查器中显示

时间:2017-06-13 20:03:28

标签: c# unity3d serialization

假设我有一个这样的课程:

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

我想使用BinaryFormatter序列化这个类。我无法序列化转换组件,因此我需要在序列化时忽略它,但我仍然需要在检查器中看到此 _transform 字段。在此示例中,只应序列化字段 _value

如果我在 _transform 字段中使用 [System.NonSerialized] ,它将无法在Unity检查器中看到,如果我使用 [SerializeField] 我无法使用BinaryFormatter序列化Transform。

看起来有点像悖论......是否可以这样做?

2 个答案:

答案 0 :(得分:1)

  

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

你不能这样做,但有一个解决方法。与scott提到的一样,请使用JsonUtilty。这不会完全解决您的问题,但会阻止您在尝试反序列化由于_transform变量引起的json数据时出错。

您只需要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

答案 1 :(得分:1)

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

我建议在场景模型和持久性/序列化模型之间分离模型。

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等)。