When writing a Unity component, it’s likely that you’ll want to expose some variables in the Unity Editor’s Inspector, so that either you or a designer can modify those values without having to recompile the script. However, the default method of exposing variables in the inspector can break class encapsulation in an undesirable way. This post explores ways to expose variables in the Inspector without sacrificing your class’s encapsulation.
The most straightforward way to expose a variable in the Inspector is to simply make the variable public. In fact, Unity’s Getting Started docs explicitly state that this is the way to do it.
public float someValue = 10.0f;
When you declare a public variable like this, it signals two important things to Unity. First, it indicates that the variable should be serialized - that is, the value of this variable is saved to disk and loaded from disk for different instances of the component. Second, Unity displays all serialized variables in the Inspector by default.
Unfortunately, there’s a big problem with this “public variable” system: it ignores a critical programming concept called encapsulation.
Encapsulation
Encapsulation is the idea that you should write “shy” classes. Shy classes don’t expose themselves to others needlessly. A shy class will only expose one of its variables or functions as “public” if it absolutely must do so.
Writing “shy” code is one of your primary tools for limiting code complexity. As a programmer, I’d argue that one of your top priorities should be to limit complexity. There are a couple rules I follow to keep my code shy:
-
All class members should use the
private
access modifier, unless a compelling reason to useprotected
orpublic
is found. -
Do not expose
public
variables. Instead access variables through Getter/Setter methods or Properties.
To elaborate on #2 a bit, exposing a public
variable is dangerous for a couple reasons. It means that any piece of code anywhere in your game can access the variable, and change it, and the class won’t know that it was changed. If you want to do some other operation when the variable changes (like log to the console or ensure the value is valid), you can’t.
It also violates the Uniform Access Principle, which states that a caller shouldn’t know whether data being accessed is stored or computed - direct variable access is obviously “stored” data!
So, we have a problem. Unity wants us to mark variables as public to indicate that they should be serialized. This, in turn, also causes Unity to display variables in the Inspector. However, exposing public variables breaks encapsulation, which, as responsible programmers, we’d like to avoid.
Serializing Private Variables
Fortunately, Unity has a solution to this problem. You can easily serialize a private variable by using the [SerializeField]
attribute:
[SerializeField]
private float myPrivateValue = 10.0f;
This will tell Unity to serialize the private field and show it in the Inspector.
If a variable should be serialized and exposed in the Inspector to designers, but not be exposed publicly in code, you should always do this!
Hiding Serialized Variables
Unity will serialize any variable that is either public, or has the [SerializeField]
attribute. Sometimes, you might NOT want a serialized field to appear in the Inspector. You can achieve this using the [HideInInspector]
attribute.
[HideInInspector]
public float dangerousPublicValue = 10.0f;
[SerializeField][HideInInspector]
private int serializedButHiddenPrivateVariable = 42;
The [HideInInspector]
attribute stops a serialized variable from appearing in the Inspector. So, you can apply it to a public variable (which is serialized by default) or a private variable with the [SerializeField]
attribute.
Don’t Serialize Public Variables
Finally, you might have a public variable that you don’t want Unity to automatically serialize. In that scenario, you can do this:
[System.NonSerialized]
public float someValue = 10.0f;
The [System.NonSerialized]
attribute stops the variable from being serialized, which in turn also stops it from being displaying in the Inspector.
Conclusion
Note that the various combinations of access modifiers and attributes cover all the use-cases for variables in relation to encapsulation and serialization:
Serialize? | Show in Inspector? | Public In Code? | Solution |
---|---|---|---|
Yes | Yes | Yes | Public Variable |
Yes | Yes | No | Private Variable & [SerializeField] |
Yes | No | Yes | Public Variable & [HideInInspector] |
Yes | No | No | Private Variable & [SerializeField] & [HideInInspector] |
No | No | Yes | Public Variable & [System.NonSerialized] |
No | No | No | Private Variable |
When designing components in Unity, it’s important to ask yourself which variables need to be serialized, which need to be exposed in the Inspector for tweaking, and which should be publicly available in code (hint: not many).
Based on your needs, there is a combination of access modifiers and attributes to get you exactly what you need!