Crash when using GameObject.Instantiate

I have submitted this to Unity via Crash Report, but I’m posting here because I need an enlightenment/solution for this problem since it’s very important and urgent to our project.

A public field or private with SerializeField attribute in a MonoBehaviour will make Unity crash if this field is from an abstract class and someone creates a clone of the MonoBehaviour using GameObject.Instantiate and then call a method from the abstract class, even if the field is not null.

The problem happens because Unity serialize it using the abstract type instead of the actual type.

The following example illustrate this problem, Unity will crash if you hit T:

public class CloningTests : MonoBehaviour
{

[SerializeField]
private SomethingMaker SomethingMaker;

void Start()
{
	SomethingMaker = new SecondObject ();
}

void OnGUI () 
{
	Event ev = Event.current;
	
	if (ev.type == EventType.KeyUp && ev.keyCode == KeyCode.T) {
		
		CloningTests script = (CloningTests)FindObjectOfType (typeof(CloningTests));
		
		CloningTests clone = (CloningTests)GameObject.Instantiate (script);
		
		clone.SomethingMaker.DoSomething ();
	}
}
}

[Serializable()]
public abstract class SomethingMaker
{
public abstract void DoSomething ();
}

[Serializable()]
public class SecondObject : SomethingMaker
{
public override void DoSomething ()
{
	Debug.Log ("Doing something");		
}
}

There are several things messy / wrong:

  • Don’t use a classname as variable name!
  • Your script clones itself so why are you use FindObjectOfType, “this” will do?
  • Your cloned Object creates a “SecondObject” in Start, but Start is called next frame so you can’t access clone.SomethingMaker right after you instantiated it. Use Awake instead of Start. Awake is called when the instantiate is finished.
  • I guess the crash happens because the clone also will produce another clone and so on but I’m not sure.
  • Besides the good will of using class inheritance your setup won’t be serialized by Unity. Unity serializes by the variable type, not the actual type. If you have a variable of type SomethingMaker but it holds a SecondObject, after serialization / deserialization it’s just a SomethingMaker. That could also cause the crash since your base class is abstract.

I had some bad times figuring out that behaviour. The only working workaround to get those instances serialized is to make them MonoBehaviours and attach them to a GameObject. GameObject-Components are the only classes where Unity serializes the “real” type.

Same problem, I’m giving up using unity, too many bugs.