C# Properties in Unity

C# Properties are one of the nicer features of C#, but there are things to keep in mind when using them in Unity. The framework doesn’t seem to like them too much. I will show you what the Unity-specific problems on using properties are and how to easily address them.

About properties

When I started writing this article, I wanted to give a brief introduction on why properties are good and why you should always prefer them instead of public fields, but I ended up digressing too much. My intentions are never to repeat whatever you can find easily online elsewhere.

Instead, I’ll send you off to a good and relatively short article on why you should use properties instead of public fields: Why Properties Matter.  And here’s a nice relevant discussion on Stack Overflow: Getters, setters, and properties best practices. Java vs. C#. Yes, these were some of the first Google results that appeared to me. You can find a lot more information if you’re willing.

However, the above does not take Unity into account. Unity violates a lot of good C# practices. Using public fields in Unity is often much simpler than using properties. The syntax to fully fix all issues is too verbose, even for the simplest properties. However, using properties in Unity is still extremely useful, so avoiding them altogether is not a good thing.

Performance issues

Games are very demanding applications, so optimization is important. It wouldn’t be nice of me to promote using properties without at least saying that properties are always slower than using public fields (the JIT which is supposed to inline simple properties doesn’t work for Unity), so do keep that in mind. Some general guidelines I suggest:

  • Avoid using them from inside their own class and use their respective private fields instead.
  • Avoid using them in small private classes, i.e for very isolated controllable situations.
  • Avoid using them in simple classes or structs that are only meant to store data.
  • Avoid using them in intensive situations where they can actually slow things down.

Getting or setting a property is only as expensive as a method call.  I can guarantee that they will rarely ever cause a problem in most cases, and the benefit of having them is often too great if you want your code to be maintainable and team-friendly.

As a bonus, here are two of my main philosophies when programming that I think everyone should follow religiously:

  • Even if you are working alone, always assume other people are working with you. At the least, future-you will be very grateful.
  • Make your classes as hard to use inappropriately as possible,  without limiting their functionality. Your users (including future-you) will try their hardest to break them. Don’t let them!
When to use Methods instead of Properties

You’d use properties when getting or setting a value that is a logical data member. Examples:

Here are some guidelines as to when to use Methods instead of properties, according to Microsoft:

  1. The operation is a conversion, such as Object.ToString .
  2. The operation is expensive enough that you want to communicate to the user that they should consider caching the result (for example, accessing a database).
  3. Obtaining a property value using the get  accessor would have an observable side effect.
  4. Calling the member twice in succession produces different results.
  5. The order of execution is important. Note that a type’s properties should be able to be set and retrieved in any order.
  6. The member is static but returns a value that can be changed.
  7. The member returns an array. Properties that return arrays can be very misleading. Usually it is necessary to return a copy of the internal array so that the user cannot change internal state. This, coupled with the fact that a user can easily assume it is an indexed property, leads to inefficient code.

One more to add to that list, which I suggest personally: Use a method to return a new reference type object. It is still ok to use them for new structs. This suggestion is a more specific version of the fourth rule.

Unity violates the second rule in versions 4.x and below. Thankfully, starting from Unity 5.0, a lot (but not all) of those properties will be removed and accessing them will require a method.

The problem with Unity

It all comes down to one thing: Serialization. For more information on Serialization, refer to my article here.

Pretty much every C# framework other than Unity prefers properties over field members. For example, the controls of .NET Winforms only show properties in the editor and not members. Unity does exactly the opposite: It completely disregards properties in the editor and only chooses to serialize public fields instead. This isn’t too bad. The problem is that your scripts will sometimes be forced to expose public fields, which can be a huge issue from a software engineering point of view.

One of the best features of Unity over other game engines is how scriptable the editor is, which provides a visual editor for your scripts and the possibility to write your own. Consider this small class:

If I simply drag and drop this script onto a GameObject, this is what we get in the inspector:

Health Man

Of the two fields, only Health shows up, because it’s public. This is due to the way that Unity serialization works. It assumes all public fields are serializable and all the private ones are not.

Only serializable fields are saved – if I set _bullets to a value while in-game, then if I make any changes to the code the value of _bullets will reset to 0. To fix this, I have to make _bullets serializable. But, what if I don’t want it to be public?

Here’s how we would do this:

Now, _bullets will be saved. As a side effect, it will now also show up in the Inspector:

Bullets

If, for some reason we don’t want that, we can add an extra attribute to the field:

And this time _bullets will still serialize, but will not show up in the inspector.

If we want to use properties instead of fields, we have a problem: Not only will properties not show in the Inspector at all, but their values will not be serialized, and there is no attribute that fixes that.

PropertiesInvisible

Fixing the problem

“Fine”, I hear you say, “we can get around that by using a custom editor.”

Yes and no. if we use this simple editor code:

The fields do show up, but any changes you make have no effect! Obviously, that is not desirable behaviour. Fixing this is simple, but, unfortunately, is a bit verbose:

Both the default editor and custom editor will work now. The reason the custom editor will work is that now it has serializable fields to transfer to the game. However, there is one important difference: The default editor edits the fields directly, whereas the custom editor (as implemented above) accesses the properties.

As such, if you have any bounds checking like this:

Our current implementation will bypass the Inspector if you use the default editor!

500Health

A simple way to fix this without resorting to a custom editor is to limit health in the Awake() function of your MonoBehaviour:

The statements:

…are logically equivalent to this:

Your inspector will still show the unacceptable values before the game starts, but if you press Play your variables will be reset to acceptable values. However, you could still bypass the checks by modifying the script via the Inspector while the game is running.

A better solution to have runtime checking in the inspector, without implementing a custom editor, is simply to implement the OnValidate() method:

The OnValidate() method is used only by the editor, and it is called automatically whenever the Inspector makes a change to your object. It doesn’t need to be public, so keeping it private is a good practice. Its usage is precisely for situations like this: it is for making sure that the new Inspector values are acceptable.

You can have all sorts of checking in this method, but setting the backing fields to their respective properties should be enough in most cases.

Bonus: Naming conventions

You might have noticed that I follow these conventions while programming in Unity:

  • Public fields are in PascalCase.
  • Private fields are in _camelCase.
  • Parameters and local variables are in camelCase.
  • Properties are in PascalCase.
  • Methods are in PascalCase.

There seem to be different opinions as to how people should name private fields. I prefer _camelCase, but other people might go for camelCase (can easily be confused with parameters) and others go for m_camelCase or something similar to that (ewww). This isn’t nearly as important as naming public members, though.

The official C# guidelines require every public member, property, method, etc to be in PascalCase. I like this convention alright, but there is a problem here: Unity’s properties are in camelCase. I believe this is because C# was not the original language and so the camelCase convention was carried off from the older days when Unity was just using UnityScript.

A lot of people who are as picky as I find this confusing: Should they name their properties after Unity’s naming style, or should they go with the official C# style?

I have tried using both in different projects, and I even tried using a structured hybrid solution in a brief moment of bad judgment (everything that derived from UnityEngine.Object followed camelCase, the rest followed PascalCase). My suggestion is to always go with the official PascalCase, so that your C# code agrees with the vast majority of C# code in this universe and every other universe in which PascalCase is the official convention.

One of the reasons behind my suggestion is that you get the potentially useful side-effect of Unity properties being easily distinguishable from your own properties. Another reason is that, starting from Unity 5.0, all default properties in MonoBehaviours will be gone (with the exception of transform). This will greatly reduce camelCase properties, which makes following that style an even less sensible choice.

The remaining problem is that Unity add-ons will have varying conventions among them. There’s nothing we can do about that.

3 thoughts on “C# Properties in Unity”

  1. Hello. Thanks a lot for the article. There is another problem with lower/upper case for properties, if you’re under MacOS and using MonoDevleop and its templates. I and my other teammate use a template that simultaneously generates a [SerializedField] private field and a get/set pair for it. The field/property name then has to be entered only once, as the template just have multiple entries for one parameter. We first were very excited to follow the official C# convention. But after about half a year it became such an annoying hiccup to every time after having entered the template going to the property name, erase the first lower case letter and type in the same in upper case. We semi- solved it by adding the $end$ parameter to the template to at least save time moving the cursor. In some time we eventually gave up and decided that since we’re in Unity, we just follow Unity guid lines. We dropped PascalCase for properties completely and are happy people now. Those who type in fields and properties manually don’t know this problem I guess.

  2. As I read this it felt like I was walking through the last half hour of my life, trying to figure out why my custom inspectors didn’t like auto-properties.

    Anyway, serializing the private backer was the answer in my case. Thanks for walking through this so clearly.

Leave a Reply