- Home /
Is there a reason not to inherit from UnityEngine.Object if I wanted the basic functionalities that UE.Object gives?
I was writing an editor to one of my objects - the object has a list of TextEntry
(`TextEntry` is a System.Object
) - I usually start my classes out as regular C# classes, and then if at one point I notice that they need to live in the scene, or need to have an update method, etc. I make them MonoBehaviours
.
The problem with dealing with System.Objects in editors, is that they don't cope too well with SerializedProperties
- if you have a SP that points to a System.Object
, you can't get the correct object reference value - since SP.objectReferenceValue
returns a UE.Object
and AFAIK there's no correct conversion between UE.Object
and System.Object
(please correct me if I'm wrong)
So I thought oh well, in this case I just want my objects to work well with SerializedProperties
, I don't want them to act as MonoBehaviours
and there's no need for them to be ScriptableObjects
too - so why not just inherit UE.Object
in this case?
I've never seen anyone do it - Is there a reason not to?
Thanks for any help.
EDIT:
Well, it seems that I can't even instantiate a UE.Object successfully!
i.e.
var o = new Object(); // o is null after that...
or
public class MyObject : Object { }
var mo = new MyObject(); // same
I looked through my code and I don't have anything that inherits from UnityEngine.Object - but I have tons that inherit from ScriptableObject - I guess if I want it to be seen in the inspector as an independent thing then I consider it to be an "asset" which is better inheriting in that path due to the ability to save them to the project folder.
It's probably a style thing - I want those things in my project I guess. Examples include:
Items for purchase in my in game shop
$$anonymous$$apping between models and clothing that fits them for my avatar system
Dialogue conversations for my NPCs
Script repository for my dynamic scripting language
BehaviourTrees for my AI
Advertisments for my SI$$anonymous$$S style requirements AI
Shop definitions for a virtual world system, full economics for those shops effectively
I tend to make them assets and dupe them then fiddle with the values.
$$anonymous$$eep in $$anonymous$$d that you can store multiple ScriptableObject in one asset by using AssetDatabase.AddObjectToAsset. However the grouping should make some sense ;)
@vexe I need them in the project - I need to refer to them without reference to a scene - they are self contained consumables. The important thing, like all project assets, is that they can refer to one another without the need for them to exist in a scene - that is not true of $$anonymous$$onoBehaviours
@vexe you use DestroyImmediate and it removes it from the container asset.
Answer by Bunny83 · Feb 22, 2014 at 12:50 PM
Yes there are reasons ;) UnityEngine.Object is the base class of all built-in Unity objects. It usually has a respective counterpart in the native part of the engine. The only two (runtime) classes you should use as baseclasses are "MonoBehaviour" and "ScriptableObject".
As you might know the scripting "engine" in Unity is Mono. Mono runs is a managed environment. It's actually impossible to destroy / delete an object instance. It's always the garbage collector which frees the memory. However we all know the Destroy method, so how does this fit? Well as i said above most objects have a native-code part and a managed part. Since we work in the managed environment we only see / can work with the managed part. Whenever you use Destroy on such an object you actually just destroy the native part of that object. The managed part is garbage collected once there are no references to the object anymore.
Unity used a hacky "trick" to make the managed part "pretend" to be null when the native part is destroyed. That's why your created "Object" seems to be null. This behaviour makes it impossible to derive your own classes directly from UnityEngine.Object. A MonoBehaviour has a native part (that's also the part where the events like Update, Start ... comes from)
UnityEngine.Object by itself only have the instanceID on the managed side. Everything else, even the "name" and "hideFlags", are implemented external, on the native code side. So without creating a proper object which has both, a managed and native side, a UnityEngine.Object is useless.
If you want a class to be serializable by unity it has to be derived from MonoBehaviour or ScriptableObject, there's no way around that. In most cases it's easier to just use MonoBehaviours especially if you need the class to be serialized in the editor. ScriptableObjects need to be serialized "on their own" as asset.
Not true that classes have to inherit $$anonymous$$onoBehaviour or ScriptableObject to be serialized by Unity.
https://docs.unity3d.com/ScriptReference/Serializable.html
https://docs.unity3d.com/$$anonymous$$anual/script-Serialization.html
It is true. You should look into how Unity's serialization system works. Custom serializable classes are not serialized on their own in Unity but are serialized as sub properties of either a $$anonymous$$onoBehaviour or a ScriptableObject.
Have you actually read all the restrictions on "custom classes" in the section "In what situations does serializer behave unexpectedly?".
All those restrictions (behaves like struct, can't be null, no polymorphism) come simply from the fact that from a serialization point of view those classes simply do not exist.
Set your "asset serialization mode" to "force text" (Edit -> Project Settings -> Editor) and look at the serialized data of your custom class by opening a scene asset or prefab asset file in a text editor. It doesn't exist. All you will see is a $$anonymous$$onoBehaviour or ScriptableObject (which is also a $$anonymous$$onoBehaviour from the native code point of view) that has some sub properties below the variable that originally referenced the custom class. So the content of a custom class is serialized "in place". Without a $$anonymous$$onoBehaviour / ScriptableObject it is not serialized at all because that's how the asset database work in Unity.
The last sentence is incorrect. ScriptableObjects can be serialized on their own without being in an asset if you create them using ScriptableObject.CreateInstance().
This is useful if you attach such objects to a $$anonymous$$onoBehavior (via serialized field), this way such object will be saved inside Scene or Prefab files, depending on where the GameObject is.
Other use case is using them for custom editors to automatically draw property fields for every serialized field when you need some settings for your editor. These would not be saved in any asset at all unless you code it yourself.
Didn't know that, is this why the ??
and ?.
are so aggravating with $$anonymous$$ono? Pretend nulls?
@TreyH it's not $$anonymous$$ono, it's UnityEngine.Object that has it's null comparison overridden. So when you write component == null
you are invoking custom Unity's check for wrapped C++ object to exist or not. But when you use ??
or ?,
operators - they are extended by C# compiler into a normal null checks for C# object. This is why you get different behavior.
Your answer
Follow this Question
Related Questions
Is there any way to successfully cast a UnityEngine.Object to a System.Object? 1 Answer
An OS design issue: File types associated with their appropriate programs 1 Answer
AddComponent asking for type which is not a Unity engine type. 0 Answers
Testing for null, bug or feature? 2 Answers
How to insert an element of specific type to a list as serializedProperty? 1 Answer