Serialization Woes

Hi there,
I am having problems with data persistence after pressing play in the editor for my editor window.
To demonstrate the problem in a clear way - copy and paste and dump this script into an editor folder:

using UnityEngine;
using UnityEditor;
using System;

public class SerTest : EditorWindow
{
    private BaseView _baseView;

    [MenuItem("SerializationTest/SerTest")]
    static void DoIt()
    {
        GetWindow<SerTest>();
    }

    void OnEnable()
    {
        if (_baseView == null)
        {
            _baseView = new BaseView();
            Debug.Log("New BaseView created");
        }
    }

    void OnGUI()
    {
        _baseView.OnGUI();
    }
}

[Serializable]
class BaseView
{
    private ViewUnit[] _array;
    private CompoundClass<ViewUnit> _compoundClass;

    public BaseView() //Constructor
    {
        _array = new ViewUnit[3];
        for (int i = 0; i < _array.Length; i++)
        {
            _array[i] = new ViewUnit();
        }
        _compoundClass = new CompoundClass<ViewUnit>(3); 
    }

    public void OnGUI()
    {
        GUILayout.Space(15);
        GUILayout.Label("Simple Array");
        for (int i = 0; i < _array.Length; i++)
        {
            _array[i].OnGUI();
        }

        GUILayout.Space(15);
        GUILayout.Label("Compound Class");
        for (int i = 0; i < _compoundClass.AnArray.Length; i++)
        {
            _compoundClass.AnArray[i].OnGUI();
        }
    }
}

[Serializable]
class ViewUnit
{
    private int _someInt;

    public void OnGUI()
    {
        _someInt = EditorGUILayout.IntField("Some Int", _someInt);
    }
}

[Serializable]
class CompoundClass<T> where T : new()
{
    private int _someInt;
    public T[] AnArray;

    public CompoundClass(int capacity)
    {
        AnArray = new T[capacity];
        for (int i = 0; i < AnArray.Length; i++)
        {
            AnArray[i] = new T();
        }
    }
}

So there is a ViewUnit which I am displaying in 2 fashions:
Once as a simple array of ViewUnits, and in the 2nd instance as an array which is part of a class.
If you try this sample out and press play you will see that in the simple array - data is preserved after play is pressed.
But all data is lost in the 2nd case.

How can I solve this? Help will be very much appreciated.

Unity has trouble serializing generic objects other than List. Does it work if you make CompoundClass non-generic as a test?

I think this is a good post on editor window serialization when switching between edit and play mode: http://forum.unity3d.com/threads/130889-Custom-Editor-losing-settings-on-Play?p=884007&viewfull=1#post884007 – might be worth a skim-over.

TonyLi you are totally correct, Unity does seem to have a problem with serializing generic objects other than List. Thanks for pointing that out. Making the CompoundClass non-generic did work.

I am going to also mention that I tried implementing ISerializable on the generic CompoundClass, but that didn’t work. I am not sure as to why it didn’t, this is what I tried:

[Serializable]
class CompoundClass<T> : ISerializable where T : new()
{
    //private int _someInt;
    public T[] AnArray;

    public CompoundClass(int capacity)
    {
        AnArray = new T[capacity];
        for (int i = 0; i < AnArray.Length; i++)
        {
            AnArray[i] = new T();
        }
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("AnArray", AnArray);
    }

    public CompoundClass(SerializationInfo info, StreamingContext context)
    {
        AnArray = (T[])info.GetValue("AnArray", typeof(T[]));
    }
}

andrey_bryzgalov posted an answer to serializing generics at Serializable class using generics - Questions & Answers - Unity Discussions

It might work in your situation.

The usual solution to have generic classes being serialized is to have you top-most class being non-generic.

public abstract class Manager<T> { }

public class UserManager : Manager<UserManager> { }

In this example, UserManager is properly serialized.

Thanks LightStriker - that works nicely too.

Bit of a necro post, but just thought I’d add that Unity has no problem serializing generics like LightStriker pointed out (if the top-most class is non-generic). However, Unity cannot serialize any generic classes that contain collections of another generic class, regardless if the derived class is non-generic.
An example of this would be:

[Serializable]
public class Bar<T>
{
    public T Value;
}

[Serializable]
public class Foo<T, U>
{
    public List<Bar<U>> GenericBarCollection;
}

[Serializable]
public class Derived : Foo<Derived, Object>
{
    // Even tho this is a non-generic class, it will not serialize because
    // of the generic list in the base class Foo<T, U>.
}