Public variable or Property?

So I got a quick one for you unity gurus :

If I have an object in a script and I want other scripts to access it, I always wonder what is the best way to do it :

Public :
My favorite, but also disliked by most programmers. I can give a value directly in the editor and when the game load it should be faster then doing a getcomponent on start/awake (form what I have read). I also can access it just by typing the name. The issue most people have with public variable is that anyone can modify it without validation. it,s bad practice.

Public property :
With this, you don’t have the issue of lack of validation. In your get/set of property, you can add code to validate your data. Sadly, it won’t shup up in the editor, and you will have to getcomponent on start.

I know everyone will tell me to no use Public variable. But then should I initiate every property on the awake/start component of my object? Won’t it be a bit slower then public variable?

Also is there another way to add a variable that can be used by another script and still show up in the editor?

P.S : If anything I say in my post is wrong, feel free to correct it.

1 Like

You can use custom editors to expose property fields.

1 Like

You can also use a combination of the 2

[SerializeField]
protected SomeType _Whatever;

public SomeType Whatever
{
    get
    {
        return _Whatever;
    }
}
4 Likes

There’s a reason that public variables and public properties both exist in the C# language, and that is because sometimes you want one, and sometimes you want the other. If you have any sort of validation or reaction to a change of a variable, it should be a property. If you find yourself checking a variable in Update and then doing something if it changed, it should probably be a property. If neither outside scripts nor the inspector need write access to a particular thing, consider making it a property.

5 Likes

@LaneFox

Is that hard to implement? I might take a look on google later today, sounds great.

If you enter your property value via the editor, it will bypass the get/set code right?

@Mordus

Good idea, but looks tedious to implement as I would have to repeat my variable each time.

And is it a non-issue that I can’t assign my property in the editor and have to do it via getcomponent?

As I have a script manager that manage other scripts, and he need to be linked to every other script so I use public variable and set to value in the Editor.

There are ways to make it possible to assign properties from the editor. Either you create a custom editor from scratch or you use an existing asset to mostly automate the process. The Vexe Framework can handle properties and it’s open source.

https://github.com/vexe/VFW

1 Like

You can also consider you can create public variables of the script itself. So a gameManager that has
public PlayerScript player; Could have a player gameobject that has the script dragged and dropped in there, thus removing the need to use getComponent and you could then just access your properties through that.

If it’s a Public GameObject player and you dragged and dropped, you’d still have to create a reference to the script using getComponent.

1 Like

Custom Editors are pretty amazing. You can make it access whatever you want, property (get/set) or the backer field (bypass). They have a bit of a learning curve and serialization caveats and maintenance to consider.

You could just expose the backer field as public if you really wanted to get it in the inspector. As long as you assume you’re always going to communicate with it through the property at runtime…

1 Like

You can use [SerializeField] to keep a field private but allow it to be modified via inspector.

3 Likes

I wish there was a [SerializeAutomaticProperty] that would do the same as serialize field, but without me having to manually write out the private backing fields.

1 Like

Didn’t realize that would make it popup in the inspector. Cool.

1 Like

Shameful question : Can you use get/set like a property can?

[SerializeField]
string test;

public void test(string par)
{
   test = par;
}

public string test()
{
   return test;
}

It wouldn’t work right? I don’t have any to test it right now.

It annoye me to right a class.gettest(“blah”), when i can just do a class.etst = “bla”;

I tried to understand this several times, but failed. So have some other code.

[SerializeField]
private string BackerField;

public string PublicField
{
   get { return BackerField; }
   set { BackerField = value; }
}
1 Like

Ahaha sorry about that, but your solution is what I was trying to do.

Have a private variable works as a public field, except that i can add validation in the get set.

I’m not a fan of dupping field (one private and one public) but if it’s the only way. :slight_smile:

That’s what you are doing anyway. The auto properties just hide it within syntactic sugar.

There really is no explicit need to use properties. A field works fine. If you need validation, you can always change it later.

This is best practice. For clarity, let’s go over a bunch of them:

  • [SerialiseField] - Used whenever a variable needs to be exposed to the inspector.
  • public - Used whenever another script needs to access a variable.
  • Auto properties - Used whenever you need different access modifies on the set or get properties.
  • Explicit properties - Used whenever you need to get clever. For example data validation, triggering on change events, complex setting or getting behaviour.
  • Method - Used whenever there are additional side effects above and beyond setting and getting a variable.

And there are a couple of bad practices you should stomp out mercilessly:

  • Using a public variable just to expose it to the inspector.
  • Using auto properties on everything, regardless of need.
5 Likes

@Kiwasi

Awesome Tips thank you!

Changing a field to a property is a breaking change. For example a field is a variable and can be passed by reference (ref or out keyword), while a property is a pair of accessors and cannot be passed by reference, thus changing a field that is passed by ref or out into a property will cause you code to break. So while you can change it later it might force some refactoring while changing a property to a field (or adding a backing field) will never be a breaking change.

Also an interesting read from the VB team (same logic applies to C# as both compile to the same IL): https://blogs.msdn.microsoft.com/vbteam/2009/09/04/properties-vs-fields-why-does-it-matter-jonathan-aneja/

You’d hate the code I write for non-Unity projects. :stuck_out_tongue:

1 Like