1
\$\begingroup\$

I have the following class to represent items in an inventory:

[System.Serializable]
public class InventoryItemInfo : MonoBehaviour
{
    public int Row = 0;
    public int Col = 0;
    public int Rotation = 0;
    public InventoryItemType ItemType;
    public int Amount;
    public int EffectiveWidth = 0;
    public int EffectiveHeight = 0;

    public int Width = 0;
    public int Height = 0;

    public bool Selected = false;
    public Vector3 TilePosAccordingToCurrentRotation;
    public Vector3 TileScaleAccordingToCurrentRotation;

    [NonSerialized]
    public Transform TheNicelyPositionedMesh;

    [HideInInspector]
    private int _iCurRow = 0;
    private int _iCurCol = 0;
    private int _iRotationToCheckForDirtyness = -1;

    public Vector3 DefaultRotation;

    public bool Initited = false;

    public bool Dirty = true;
    private bool _bInitialRotationGotten = false;
    (...)

With the keyword [NonSerialized], the property "TheNicelyPositionedMesh" disappears from the Unity Inspector.

I don't see why. Why is that keyword coupled with the visibility in the Inspector?

Thank you!

\$\endgroup\$
1
  • \$\begingroup\$ I'm curious what you intend to do with an inspector field that's not saved to a file so that the edit-time data you put into it survives into your built/running game. Is this just for helping you monitor some transient state while testing the game in the editor? \$\endgroup\$
    – DMGregory
    Jul 10, 2019 at 10:51

2 Answers 2

4
\$\begingroup\$

Because Unity 'stores' public variables and private variables marked with the SerializeField attribute by serializing them. By using the NonSerialized attribute you can tell Unity that you don't want Unity to serialize it even when it normally would.

The inspector shows only serialized values in the inspector because these are the only ones that are actually stored/saved on disk.

If you change a value in the inspector, Unity handles serialization of that new value.

When you then Instantiate the object (either by calling Instantiate for prefabs or entering/exiting playmode for object in the scene), Unity will overwrite the default values of these serialized fields with the values you have set in the inspector. Unity does this before invoking Awake.

Values that are not serialized will therefore not be overwritten by values set in the inspector, so showing (editable) NonSerialized variables in the inspector doesn't make sense because any changes you do to them will be reverted back to their default values (set in the script) whenever Unity serializes/deserializes.

There are still valid usecases for when you want to see and prehaps even modify non serialized values in playmode. But as far as I'm aware Unity doesn't have an attribute to show non-serialized variables , not even as read only. The only way to show those is by either making them serialized, temporarily using the debug inspector or writing a custom inspector.

See also this section of the manual.


EDIT:

To clarify when Unity serializes something, first of all, if you haven't read that section of the manual. you really should.

Here is a short summary which might or might not be easier to understand then the manual, but it won't cover everything, so read that manual if you really want to know how everything works ;)

Unity can serialize any type that is one of the following:

  • All classes that derive from UnityEngine.Object, for example GameObject, MonoBehaviour, etc.
  • All basic data types like int, string, float, bool.
  • Some built-in types like Vector2, Quaternion, etc.
  • Enums
  • custom classes or structs marked with the [Serializable] attribute
  • Arrays of a serializable type
  • List of a serializable type

Unity will then of those classes that it can Serialize, Serialize all its:

  • public variables that are not marked with [System.NonSerialized]
  • private variables marked with [SerializeField]

Note that it can only serialize fields of which the type is Serializable by Unity as explained above.

Fields marked with [HideInInspector] are still serialized (if it passes above criteria), they are just not show in the inspector.

Code explains more then words, so here is a small exmple which I hope covers everything.

[System.Serializable]
public class MyClass1 // Serialized, because we marked it with [System.Serializable]
{
    public int i1; // Serialized, because Unity can serialize int, field is public and MyClass1 is Serializable
    private int i2; // Not Serialized, because field is private
    [SerializeField] private int i3; // Serialized, Because Unity can serialize int and field is marked with [SerializeField] attribute.
}

public class MyClass2 // Not serialized, because we aren't [Serializable]
{
    public int i1; // Not serialized, because MyClass2 isn't [Serializable]
    private int i2; // Not serialized, because MyClass2 isn't [Serializable] (And we are private)
}

public class Example : MonoBehaviour // Serialized, because MonoBehaviour inherrits from UnityEngine.Object
{
    public MyClass1 c1; // Serialized, because we are public and MyClass1 is Serializable
    private MyClass1 c2; // Not Serialized, because we are private

    [SerializeField] private MyClass1 c3; // Serialized, because we are marked with [SerializeField] and MyClass1 is serializable
    [System.NonSerialized] public MyClass1 c4; // Not Serialized, because even though the field is public AND MyClass1 is Serializable, we are marked with [System.NonSerialized]

    public MyClass2 c5; // Not Serialized, because even though we are public and Example is Serialized, MyClass2 isn't Serializable

    public GameObject c6; // Serialized, because field is public and GameObject inherrits from UnityEngine.Object (And is therefore serializable).
}
\$\endgroup\$
3
  • \$\begingroup\$ Thank you. If you don't specifiy "[Serializable]", the properties are not serialized either, but the Inspector still shows the values. I thought "[Serializable]" and "[NotSerialized]" indicate whether a class / a property can / will be serialized to a file. Do you / Unity use the word "serialize" in a different sense? \$\endgroup\$
    – tmighty
    Jul 9, 2019 at 22:50
  • \$\begingroup\$ You assume that you need to mark everything [Serializable] for it to be serializable for Unity, that is not the case. See my edit, MonoBehaviours are still serializable by Unity, despite lacking the Serializable attribute. The default inspector really only show values that are serialized by Unity. \$\endgroup\$
    – troien
    Jul 10, 2019 at 10:31
  • \$\begingroup\$ Your answer is great, but it isn't the answer to my question. However, please don't delete it. I will post what I assume the most appropriate answer to my question. It comes from Unity support. Please don't delete your answer, it's an excellent piece of information, ok? Thank you again! \$\endgroup\$
    – tmighty
    Jul 12, 2019 at 16:29
1
\$\begingroup\$

The Unity bug report team admitted that the keyword [NonSerialized] doesn't perfectly indicate what it does. In fact, it does more: It also hides the property from the Inspector.

They told me to post a change suggestion at the Unity forums (now that the feedback section is no longer valid): https://forum.unity.com/forums/scripting.12/

As a workaround, they suggested the following:

"In order to create a field which is not serialized but visible in the editor, you will need to create a Custom Editor.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .