Serializable class using generics

I have a problem with a recently modified class not showing up in the inspector.

I am attempting to make a class which I can use to automatically stitch up generic list of key/value pairs into a dictionary. However, I am unable to get the class to show up in the inspector when it is added to a behavior. This was working, until I modified the class to act more like a data container by modifying the logic to allow for the getData and setData methods.

I am including the new non-functioning code, as well as an example behavior that I was using to test.


[System.Serializable]
public class MapList<Key, Data>
{


	//Should never be accessed directly in code
    //but needs to be public for serialization

	public List<Link> maps;    	

	public Link nullLink;

	private Dictionary<Key, Link> m_dict;

	protected Dictionary<Key, Link> stitchedDict{
		get{
			if (
				this.maps == null
 				|| this.m_dict == null
				|| this.maps.Count != this.m_dict.Count
			) {

				restitchDict ();

			}

			return this.m_dict; 

		}

		set{ this.m_dict = value; }

	}


	public Data getData (Key key)
	{

		if (this.stitchedDict.ContainsKey (key)) {

			return this.stitchedDict[key].data;

		} else {

			return this.nullLink.data;

		}

	}


	public void setData (Key _key, Data _data)
	{
		if (this.stitchedDict[_key] == null) {

			Link dataMap = new Link ();

			dataMap.key = _key;

			dataMap.data = _data;

			this.addMap (dataMap);

			this.restitchDict ();

		} else {

			this.stitchedDict[_key].data = _data;

		}

	}


	protected void restitchDict ()
	{

		if(this.m_dict == null){

			this.m_dict = new Dictionary<Key, Link> ();

		}

		this.m_dict.Clear ();

		this.validateMaps ();

		foreach (Link nextMap in this.maps) {

			this.m_dict[nextMap.key] = nextMap;

		}

	}


	protected void addMap (Link _dataMap)
	{

		this.validateMaps ();

		this.maps.Add (_dataMap);

	}


	protected void validateMaps ()
	{

		if (this.maps == null) {

			this.maps = new List<Link> ();

		}

	}

	

	//INTERNAL CLASSES
	[System.Serializable]
	public class Link
	{

		public Key key;

		public Data data;

	}

}

public class ExecBehavior : MonoBehaviour {
	
	public MapList<string, int> exampleMap;
	public List<string> compare1;
	public List<int> compare2;

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

You can not serialize a class using the Unity serializer if it has fields with generics.

[Serializable]
public class GenericClass<T>
{
  public T someField;
}

[Serializable]
public class SomeClass
{
   public GenericClass<string> stringClassField; //does not serialize
}

However you can define subclasses for constructed generic types:

[Serializable]
public class GenericClassOfString : GenericClass<String>
{
}

[Serializable]
public class SomeClass
{
   public GenericClassOfString stringClassField; //serializes
}

Unity uses it’s own serialization which doesn’t support generic types because that would be the hell to implement. Even a class like this can’t be serialized by Unity just because it has a generic parameter:

[System.Serializable]
public class TestClass<T>
{
    public int number;
}

Furthermore you used your internal Link class in your List<>, but Link depends on one of your generic parameters. Now i dare you to write a serializer that can handle this setup :wink:

Generics work way different to c++ templates where it’s just a search&replace at compile time. Generics are compiled as they are. It’s even hard to describe how they work :wink:

Generic type serialization alone with all the cases Unity doesn’t support is what I offer in VFW. I make use of ISerializationCallbackReceiver and FullSerializer to write a better custom serialization system. Sick of the fact that Unity’s not taking action towards this subject. While there are private individual solutions, they’re either kept private or sold at the asset store. This stuff should be available to us out of the box let alone a free downloadable package.

In VFW you could go wild and even serialize nested generic types, so you could write (not that this is realistic, but just to give you a flavor of what you can do):

public class Test : BetterBehaviour
{
   [Serialize] // makes it both serializable and thus exposed 
   private Dictionary<Tuple<string, int>, List<IOwner<GameObject>>> dictionary { get; set; }
}

public interface IOwner<T>
{
   T Value { get; set; }
}

Since I didn’t see anyone specifically mention it here you can inherit from a generic type that is a MonoBehavior also.

[Serializable]
public class MyGeneric<T> : MonoBehavior {
    public T Variable;
}

public class MyImplementtion : MyGeneric<int> {

}

As far as I can tell Variable will serialize as long as the type given is serializable.