Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

When to use Public or Private when declaring variables?

This may be a really basic question but I’m hoping for some clarification, and the reason for the post is because recently I’ve been told repeatedly and seen in other posts to never use public when declaring a variable so I’m a bit confused. This also includes [SerializeField]. I try to use private to declare variables whenever I can, but when I need to reference a variable from another script I need to change the variable from private to public otherwise I get the "variable is inaccessible due to protection level". Is that acceptable or is there a way around this?

Because currently I have around 30 variables in one large script of mine and 25 of the 30 are all public.

// ScriptA
public bool testBool;
private bool testBool;
[SerializeField] private bool testBool;

If I was to reference one of those three bools in another script (for example ScriptB), only the public bool testBool would work, and the same would apply if I used a float, Vector3, and so on instead of a bool.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

And when using something like [SerializeField] private bool testBool; This also gives the same "inaccessible" error when trying to use that bool inside of a different script so I’m just curious if I should do anything or just leave it and continue with my approach.

>Solution :

In general you want to make all things as little accessible as possible (Encapsulation)!

So things should be in this order

  • as private as possible (therefore it is also the default/implicit accessibility for type members)
  • protected in case of inheritance requires it
  • internal – meaning only accessible to everything within the same assembly (also default accessibility for types – people using public most commonly is a bad habit imho – in which I fall myself 😉 )
  • and finally public if it actually provides some global API and is required outside of the assembly

(For some very special and edgy cases – like e.g. Tests – you can also expose certain assembly bridges via [InternalsVisibleTo])


Also in general in c# it is kinda common practice to rather use properties for anything public (see e.g. Is it bad practice to use public fields?)

In very short: They basically are getter/setter methods. These can either have a backing field and implement additional logic or be auto-properties like the example below. Additionally you can control the set(ter) part’s accessibility (in theory you can also for the get but it is quite unusual to have a set with a higher accessibility than a get)

Unity even undocumented supports the auto-properties to be serialized in the Inspector using

[field: SerializeField] public bool SomeBool { get; private set; }

… so no, public fields is not the only way to provide values to other scripts.


There are many many ways – so basically it comes down a bit to preferences and your use case.

In general I would go for

// This is only used by this type
private bool someBool; 

if this is required to be adjusted by the user – aka Inspector

// This is only used by this type
[SerializeField] private bool someBool; 

and if it is required to be read by another script you can either go

// That's the backing field approach
public bool SomeBool => someBool;

// equals
public bool SomeBool
{
    get => someBool;
}
// equals
public bool SomeBool
{
    get
    {
        return someBool;
    }
}

or as said use the serialized auto-property

[field: SerializeField] public bool SomeBool { get; private/*or protected*/set };

and only if other scripts also set this you can use a

// For simplicity and less typing effort
// I also use this for fast prototyping and quickly expose things in the Inspector
// but this shouldn't stay the long-term code
public bool SomeBool;

For runtime stuff you can simply stick to

// Can have a default value and behaves similar to a public field
public bool SomeBool { get; set; }

but you can also expose it in the Inspector if needed

[field: SerializeField] public bool SomeBool { get; set; }

Auto-properies can – like fields – also be directly initialized with a value.


Sidenote: The serialized property comes with a little hickup regarding custom Editor implementations – you have to go through the virtual backing field serializedObject.FindProperty($"<{propertyName}>k__BackingField")

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading