Refactoring


Renaming Fields and Properties

When renaming fields or properties you can use either Unity's FormerlySerializedAs or Odin's PreviouslySerializedAs attributes to let Odin know how to map old serialization data to the new fields.

[FormerlySerializedAs("oldName")]
public int NewName;

We recommend using Unity's FormerlySerializedAs in favor of Odin's PreviouslySerializedAs, because Unity only supports one of them, but Odin supports both. Odin's variant was added to support the rare (and not recommended!) case of property serialization.

An important note here is that you cannot transfer serialization data between Odin and Unity with this. If a field has been serialized by Unity, then you cannot use this to deserialize it as an Odin field. See the section on Transfering from Unity to Odin for more information on this.


Renaming Types

Refactoring types can be done with Odin by using the BindTypeNameToType attribute. This lets you specify the old type name, and the type to deserialize the type as.

// Of course, you can also rename the namespace with this attribute.
[assembly: BindTypeNameToType("MyOldNamespace.MyNewTypeName", typeof(MyNewNamesSpace.MyNewTypeName))]

namespace MyNewNamesSpace
{
	public class MyNewTypeName { ... }
}

Of course, this attribute only works with Odin-serialized data.


Transfering from Unity to Odin

Renaming types and fields is all well and good, but sometimes you might want to transfer data from Unity to the Odin serializer, or vice-versa. There is no attribute you can employ for this, and requires work to be done in a few sequential steps in order to ensure that you're not losing any data.

Just renaming, or changing the data format from something Unity can serialize to something Odin can serialize, might result in your data disappearing (by the way, we always recommend using version control; you can always revert mistakes then).

It would be better to simply duplicate your fields, change the new one to be Odin serialized, and manually transfer and copy data when the object is deserialized.

public class MyMono : SerializedMonoBehaviour
{
	// We'll just hide the old data in the inspector, so it doesn't show up there and confuse anyone.
	[HideInInspector] 
	public List<MyClass> OldList;

	[NonSerialized, OdinSerialize]
	public List<MyClass> NewList = null;

	// The OnAfterDeserialize method is defined in the SerializedMonoBehaviour class,
	// but you can also use the ISerializationCallbackReceiver with Unity, and Odin
	// also supports the serialization event attributes defined in
	// the System.Runtime.Serialization namespace, like [OnDeserialized].
	protected override OnAfterDeserialize()
	{
		if (this.NewList != null)
		{
			// In this case we'll just copy the old list, but you can do
			// whatever is appropiate for your usecase.
			this.NewList = this.OldList.ToList();
			
			// At this point it may also be a good idea to mark the object as dirty,
			// so Unity will re-serialize it.
		}
	}
}

[Serializable]
public class MyClass
{
	...
}

By doing this, your data will be copied from the old format to the new.

Keep in mind that Unity doesn't always re-serialize and save objects all the time, so you cannot remove the old list right away. You'll want to either keep it around for a while, or force Unity to re-serialize all of the objects in your project. Since Unity 2018.1, the AssetDatabase.ForceReserializeAssets API has been made available in Unity - invoking this should cause your data to be migrated across the whole project.