2 problems with serialization of a generic list of a custom class

Hi. I have a serious problem with the serialization of a list of my custom class (LevelInfo) inside of the container class (Information) I want to serialize. I’m using the simple state saving script.

The minor problem is, that the private fields of my class do not get serialized.
The main problem is, that when I save Information class and then load it again, the Levelinfo list gets another set of fresh entries. This results in clogging the list with unusable information and I have no clue what went wrong.

Any help is higly appreciated. Thanks in advance.

LevelInfo class:

[System.Serializable]
public class LevelInfo{
	[SerializeField]
	private float levelTime;   //Does not get serialized, despite of [serializefield]

	public float parTime;    //This does. Set to public for testing purpose
	//...

	public LevelInfo(){	***  } //Blank Constructor
	public LevelInfo(float parTime){ ***} // other constructor

	public float ParTime{ get{return parTime;}}	
	public bool BeatPartime{get{return (levelTime <= parTime);}}
	public void BeatLevel(float time){levelTime = Mathf.Min(levelTime, time);}
	//...
}

Information class:

[System.Serializable]
public class Information{
	[SerializeField]
	public List<LevelInfo> levels;
	//...

	//This is inside of the Information constructor.
	//This is the only place I use any LevelInfo constructor.
	private void CreateLevelList(){  
		levels = new List<LevelInfo>();
		levels.Add(new LevelInfo(4.0f));
		//...
	}
}

InformationTransport class:

public class InformationTransport: MonoBehaviour {
	public Information info;

	void Awake () {
		LoadInfo();
	}
	private void SaveInfo(){
		StateStorage.SaveData<Information>(saveKey, info);
	}
	private void LoadInfo(){
		Information newInfo = StateStorage.LoadData<Information>(saveKey);
		if(newInfo == null)
			info = new Information();
		else
			info = newInfo;
	}

StateStorage class:

public class StateStorage{

public static T LoadData<T>( string key ){
	if ( PlayerPrefs.HasKey( key ) ) {		
		XmlSerializer serializer = new XmlSerializer( typeof( T ) );
		Debug.Log(PlayerPrefs.GetString( key ));
		StringReader sr = new StringReader( PlayerPrefs.GetString( key ) );
		return ( T )serializer.Deserialize( sr );
	}else{
		return default(T);
	}
}	

public static void SaveData<T>( string key, T source ){
	XmlSerializer serializer = new XmlSerializer( typeof( T ) );
	StringWriter sw = new StringWriter();
	serializer.Serialize( sw, source );
	Debug.Log(sw.ToString());
	PlayerPrefs.SetString( key, sw.ToString() );
	PlayerPrefs.Save();
}

public static void ClearData( string key ){
	PlayerPrefs.DeleteKey( key );
}

}

Try doing it after inheriting the “ScriptableObject” class

public class LevelInfo : ScriptableObject {

Then create an instance by doing this:

ScriptableObject obj = ScriptableObject.CreateInstance(typeof(LevelInfo));

Then, read this… very good information on serialization in unity
http://forum.unity3d.com/threads/155352-Serialization-Best-Practices-Megapost

The reason I post this is because I see no reason why you cannot use the built in serialization methods for the above code.

Doesn’t look like you have getters/setters for your private fields. How is it supposed to access that? To serialize an object you need a basic no argument constructor and a getter and setter for each attribute in the object.

Regarding the [SerialzeField] problem: I gave my properties a setter in addition to their getter. Resulting in the properies getting serialized. I also reported a bug since the expected behaviour does not match the documentation.

Regarding the clogging list: The problem was the CreateLevelList() method inside of the constructor of the Information class. The StateStorage class uses this constructor which results in the list beeing fully generated. Then it proceeds to add the saved list items on top of that.

I fixed this by removing the CreateLevelList() method from the constructor and calling it from outside when there was no saved data to load.