Reputation: 251
Let's say I have a class like this:
[System.Serializable]
public class Item {
private Transform _transform;
private float _value;
}
I want to serialize this class using BinaryFormatter. I can't serialize Transform component so I need to ignore it while serializing but I still need this _transform field to be visible in the inspector. In this example only field _value should be serialized.
If I use [System.NonSerialized] on _transform field it won't be visible in the Unity inspector and if I use [SerializeField] I can't serialize Transform with BinaryFormatter.
Seems a bit like a paradox... Is it possible to do so?
Upvotes: 5
Views: 11775
Reputation: 1858
I would not recommend using your scene objects or domain objects for serialization as well. You will always be battling between the two different serialization requirements.
I would recommend separating your models between scene model and persistence/serialization model.
public class SerializableItemModel
{
public Vector3 position;
public Quaternion rotation;
public float _value;
}
Then have a mapper than can map between your objects.
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);
}
}
If you separate your objects like this you will never have to worry about cross cutting concerns like serializing your object for persistence and also somehow display it in the inspector etc. If you want to serialize only 10% of your scene object then you map it into a small model and serialize that instead.
Of course this is a lot more code than you probably were hoping to write. If you wanted to you could just provide the Item to the SerializableItemModel constructor and skip the mapping layer.
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;
}
}
Now your code will look like this when serializing:
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);
}
EDIT: As pointed out by Programmer I never addressed the inspector view for Item. Because the Item class now only has one responsibility you are welcome to put [SerializeField] on any field because this object will not be used for any other serialization. You can now also use any serializer you want (JsonUtility, BinaryFormatter, JsonConvert, XmlSerializer, etc).
Upvotes: 3
Reputation: 125455
I can't serialize Transform component so I need to ignore it while serializing but I still need this _transform field to be visible in the inspector.
You can't do this but there is a workaround. Like scott mentioned, use JsonUtilty
. That will not completely solve your problem but will prevent giving you error when you try to de-serialize the json data due to the _transform
variable.
You only need position, rotation and scale from the Transform
class and all these can be serialized since they are either Vector3
or Quaternion
but Transform
cannot be serialized. So you have to declare position, rotation and scale and get their values from the _transform
variable. You can then serialize those 3 values.
[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;
}
}
Call the updateValues()
function before serializing the object to json.
void Start()
{
Item item = new Item();
...
...
item.updateValues();
string json = JsonUtility.ToJson(item);
Debug.Log(json);
}
By using json you will not have any problems while serializing the data. If you plan on saving this then look into a simple wrapper I made to handle all these.
Upvotes: 2