Best practise access levels with Unity

The solution to the issue of health and characterClass in ProgressionCharacterClass for the GetHealth(…) method given is to set the respective fields as public. Does this not set up possible issues with potential improper access levels to the progression data? Also is this a workaround to get things to play nice with Unity’s editor?

I tried a solution using properties with appropriate get/set levels but quicky learned Unity does not support serializing properties.

Thanks

@Jonholio , you are right, you cannot serialize properties but you can have a private serialized field and then getter and setter with the broader access levels. That would be something like:

[SerializeField]
private int _health; //This will be editable from the inspector

public int Health => _health;

This way the _health cannot be set from outside the class but Health is available

That’s exactly the kind of clarification I was after. Thanks!

1 Like

Actually, if you’re using Unity 2021 or later, you can use the [field: SerializeField] syntax for auto properties…
For example:

[field: SerializeField]
public int Health {get; private set;}

This will allow you to expose Health to the inspector, but still have be a read-only property within C# itself. The compiler automagically creates a hidden backing field.

Unfortunately, this construction does not support custom getters and setters, or even setting a default value, just the auto-property setup shown above.

2 Likes

Woah, that is great!

Yes it does, very simple fix I add is:

     class ProgressionCharacterClass
        {
            [SerializeField] CharacterClass characterClass;
            [SerializeField] float[] health;

            public float[] Health => health;
            public CharacterClass GetCharacterClass => characterClass;
        }

Added public Readonly Getters, so the original values cannot be modified but the values can be accessed publicly.

Be aware that this exposure of Health will prevent assignment, i.e.

Health = new [];

but you can still alter the value of elements within the array so for example

progression.Health[0] = 5000;

will still be valid.

1 Like

Ops my bad I didn’t realize that you could still change the value of the elements, thank you for pointing that out.

I’ve just tried googling how to make an arrays elements unchangeable/readonly but I can’t find anything on it, is there a way to do that?

I found something called ImmutableArrays:

But you have to install a nu package and even after doing that I’m getting errors saying namespace doesn’t exist and I think there are some complications with APIS and unity.

It may be relying on packages that don’t exist in Unity’s version of C#.

There’s actually a simpler way in this case (remember, though, this is all theory, because Sam’s about to gut the way the lookup works because you’re going to want more stats than just Health, right?

public int[] Health 
{
    get
    {
         int[] result = new int[health.Length];
         for(int i=0;i<health.Length;i++);
         {
              result[i]=health[i];
         }
         return result;
    }
}

But that looks unwieldy, fortunately, the Linq library has an answer (you’ll need using System.Linq; in your using clauses for this)

public int[] Health => health.ToArray();

This will return a copy of health, leaving the original intact. The copy is still mutable, but at the end of the method that retrieved it, no changes will be written back to the original.

1 Like