[Resolved] UnityEngine.Object instantiation

Hey guys,

Searching for an answer

Did a google search and then a search on here - also have looked through the docs but as per usual Unity seem to not provide much information about some basic aspect of their API that I’m befuddled by - but am yet to find anything on the subject; maybe I’m just not searching the right things.

The Situation

So recently I’ve started looking in to building custom inspectors using the Editor classes, and for the most part have not run in to anything I couldn’t find a quick answer to, until now. I have a class with a private field that I want to have editable through the inspector but only be read only through code. The general solution for this is to just mark it as [SerializedField], which I can confirm works in every other use case I’ve implemented.

However, I’m using a completely custom inspector (not using the draw default method). Looked this up and the workflow seems to be to use the SerializedObject class as a wrapper for my instance. The issue here being that my class doesn’t inherit from UnityEngine.Object. As it stands, the class just inherits System.object (by default as no explicit base class is specified) so I thought I’d just be able to inherit from UnityEngine.Object and all would be well…

The Problem

Bringing us to the actual problem: I instantiate the class via the usual method ( new MyClass() ), but now that it’s subclassing the Unity Object class it seems to always be null. So my code is like this:

var instance = new MyClass();
Debug.Log(instance);

When it inherits from Object, that logs as null, without the inheritance, it works fine. So is there some caveat to instantiating the Object class? Do I need to subclass something else instead? Or is it one of those Unityisms?

Thanks in advance for any insight anyone can give me.

Isn’t the unity Object class always null until you have instantiate an actual object in the game? So by saying “new MyClass()” you are not really creating a new instance. don’t know if this is correct what I am saying though…

So long as the class isn’t abstract, static or doesn’t have some other error handling in place for calling the constructor (a la MonoBehaviour) then the “new” operator is how you create instances of a class. At least within the realms of general programming. Tis why I wasn’t sure if this was some odd Unityism with its Object class, as I’m not getting any errors upon calling the constructor.

Yes. If you really want to derive from classes that are not attached to game objects, have a look at scriptable objects

You use the CreateInstance method when using this.

Thanks, that’s good looking out. Still find it odd that they’d provide a base class that doesn’t do anything. Surely they should’ve implemented some kind of warning or error to be thrown. Ah well, thanks again.

Why subclassing UnityEngine.Object should never be done, but is still possible

Unity has a c++ engine component, and a c# scripting side. Everything that is a UnityEngine.Object needs to exist on both the c++ and the c# side for the engine to work with them.

If your MyClass derives from UnityEngine.Object,

If you use your own constructor, the c++ side will not be informed of the thing being created, which will cause problems. The == operator has been overriden for UnityEngine.Object, and checks if the object exists on the c++ side when you compare with null. If it doesn’t, x == null returns true even if x is not null.

UnityEngine.Object should no be derived from by users. But, since the engine internally needs to inherit from it, and we want to be able to reference a UnityEngine.Object by it’s type, it can’t be sealed or internal. If the C# language allowed for a class to be inheritable only from within it’s own assembly, UnityEngine.Object would have that setting.

If you need a drawer for your own class, the workflow is to mark the class as [Serializeable], and create a PropertyDrawer for the class. That will cause the default drawer for any MonoBehaviour you have your class as a field in to draw the class the way you implemented it. If you’re not using the default drawer (ie. the MonoBehaviour has a CustomEditor that doesn’t use DrawDefaultInspector), you can layout the object with the DrawProperty methods of EditorGUILayout or EditorGUI classes.

ScriptableObject is, on the other hand, for objects that you need to store on disk. This means, in particular, that you can’t have a public field on a MonoBehaviour that’s a ScriptableObject, and then modify it on a script-by-script basis like you would an int or a Vector3 or whatever. Instead, you’ll have to create the scriptable object, and drag it into the field.

4 Likes