Question about Unity serialize system
Hi, i have a question about unity serialization system. these is pseudo code about problem.
[System.Serializable]
public class Parent
{
public int a;
public Parent()
{
a = 111;
}
}
[System.Serializable]
public class Child : Parent
{
public int b;
public Child()
{
b = 222;
}
}
[System.Serializable]
public class SOTest : ScriptableObject
{
public List<Parent> _database = new List<Parent>();
}
SOTest class has List field and i add few instances that is child instance as below.
public class test : MonoBehaviour
{
SOTest _database;
void OnGUI()
{
if (GUILayout.Button("open"))
{
// load ScriptableObject
}
if (GUILayout.Button("create"))
{
// save ScriptableObject
}
if (GUILayout.Button("add"))
{
Parent test = new Child();
_database._database.Add(test);
}
if (GUILayout.Button("show"))
{
for (int i = 0; i < _database._database.Count; i++)
{
Child child = _database._database[i] as Child;
if (child != null)
{
Debug.Log(child.a + " " + child.b);
}
else
{
Debug.Log("there is no child");
}
}
}
}
}
Problem is
i try to add child instances to database scriptableobject by push add button on screen.
then if i push show button, log shows me "111 222" that is exactly i expected.
then i save database object on disk.(serialization)
restart unity.
Load database object from disk.(deserialization)
push "show" button. BUT, Logs are "there is no child".
i think when i use generic list, deserialization from disk will retrieve exactly type of List. so if i add some kind of derived instance to list then serialization will lose derived class information. Am i right?
if i am wrong, how can fix this problem
thank you.
How do you serializing and deserializing? what is the procedure?
Answer by sckyj · Apr 07, 2016 at 12:52 AM
This is full code i tested.
[System.Serializable]
public class Parent
{
public int a;
public Parent()
{
a = 111;
}
}
[System.Serializable]
public class Child : Parent
{
public int b;
public Child()
{
b = 222;
}
}
[System.Serializable]
public class SOTest : ScriptableObject
{
public List<Parent> _database = new List<Parent>();
public static ScriptableObject Create(string folder, string file)
{
string fullPath = folder + "/" + file;
SOTest database = AssetDatabase.LoadAssetAtPath(fullPath, typeof(SOTest)) as SOTest;
if (database == null)
{
if (!AssetDatabase.IsValidFolder(folder))
{
AssetDatabase.CreateFolder(null, folder);
}
database = ScriptableObject.CreateInstance<SOTest>() as SOTest;
AssetDatabase.CreateAsset(database, fullPath);
AssetDatabase.SaveAssets();
}
return database;
}
}
public class test : MonoBehaviour
{
string _assetFullPath;
string _assetFolder;
string _assetFile;
SOTest _database;
void OnGUI()
{
if(GUILayout.Button("open"))
{
Open();
}
if (GUILayout.Button("create"))
{
Save();
}
if (GUILayout.Button("add"))
{
Parent aa = new Child();
_database._database.Add(aa);
}
if(GUILayout.Button("show"))
{
for(int i=0; i<_database._database.Count; i++)
{
Child child = _database._database[i] as Child;
if(child != null)
{
Debug.Log(child.a + " " + child.b);
}
else
{
Debug.Log("there is no child");
}
}
}
}
public void Open()
{
_assetFullPath = EditorUtility.OpenFilePanel("Open Database", Constants._item_Db_FullPath, "asset");
if (_assetFullPath != "")
{
LoadDatabase();
}
}
public void Save()
{
_assetFullPath = EditorUtility.SaveFilePanel("Create Database", Constants._item_Db_FullPath, "New Database", "asset");
if (_assetFullPath != "")
{
LoadDatabase();
}
}
public void LoadDatabase()
{
if (_assetFullPath != null)
{
string absolutePath = Path.GetDirectoryName(_assetFullPath);
int index = absolutePath.IndexOf("Assets");
_assetFolder = absolutePath.Substring(index);
_assetFile = Path.GetFileName(_assetFullPath);
// DB Load
if (_assetFolder != "" && _assetFile != "")
{
_database = SOTest.Create(_assetFolder, _assetFile) as SOTest;
}
}
}
}
try marking it dirty after you alter the database with SetDirty in this case
EditorUtility.SetDirty(_database);
now when you save scene with Ctrl+S it will be saved.
Thanks for your reply. I try to follow your comment but it doesn't work.
if (GUILayout.Button("add"))
{
Parent aa = new Child();
_database._database.Add(aa);
EditorUtility.SetDirty(_database);
}
i even try this but doesn't work too.
if (GUILayout.Button("add"))
{
//Parent aa = new Child();
Child aa = new Child();
_database._database.Add(aa);
EditorUtility.SetDirty(_database);
}
Try Debuging "database " object after this line:
SOTest database = AssetDatabase.LoadAssetAtPath(fullPath, typeof(SOTest)) as SOTest;
It is possible that it might not find the asset and create a new one each time.
Everything looks fine... please try Debugging "_database._database[i]" before casting to Child. and debug it after casting it into child.
I'm sorry for late for testing. i tried debug before & after _database._database[i]. When i create database both instance show me that is Child. but After restart unity and load database, both instance is Parent. ah.... i'm so confuse..
Your answer
![](https://koobas.hobune.stream/wayback/20220612074302im_/https://answers.unity.com/themes/thub/images/avi.jpg)