Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Lockstep · Jan 20, 2014 at 05:29 PM · listserializationsavegenericsserializable

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 );
 }
 

}

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Lockstep · Jan 21, 2014 at 12:07 AM

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.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by Uncasid · Jan 20, 2014 at 06:52 PM

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.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Lockstep · Jan 20, 2014 at 11:33 PM 0
Share

Thank you for your reply and the informative link.

Unfortunately the ScriptableObject does not work with the stateStorage script since it does not use a constructor. It also does not seem needed, since I'n only refering to each object once.

I tend to believe, that the missing serialization is due a bug. I guess I will simply make my stuff a bit more public.

Neverless the main problem remains. The clogging of the generic list each time I load my class.

avatar image
0

Answer by Slobdell · Jan 20, 2014 at 06:32 PM

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.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Lockstep · Jan 20, 2014 at 11:20 PM 0
Share

Thank you for your reply.

From the documentation and also from the link provided by uncasid, the [SerializeField] modifier would allow me to serialize the private field directly. Unless I'm using this wrong, it seems to be broken.

If you use getters and setters, then their corresponding property gets serialized, not the private field behind them.

I.e. this:

 public class someclass{
     private int someint;
 someclass(){
     someint = 5;
 }
     public int Someint{
         get{return someint;}
         set{someint = value;}
     }
     public int RandomInt{
         get{return 3* someint;}
         set{someint = 2* value -7;}
     }
 }

would be xml serialized into this (with the Statestorage script):

 <Someint>5</Someint>
 <RandomInt>15</RandomInt>
 

and after loading someint would be 23. If you would flip the lines of code for Someint and the RandomInt, the result would still be 5 though. And yes I tested it.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

20 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Getting any type in Unity Inspector 1 Answer

List Contains false after playmode 0 Answers

Serializing specialized subclasses of generic classes not working 1 Answer

A node in a childnode? 1 Answer

Error serializing a class to save / load 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges