Ensuring single reference that updates everywhere (for cached references)

Hey all, I’m having some reference issues.

I have a UserData class that stores some information about a user:

public class UserData
{
    public int Health { get; set; }
}

Then I have a GameData class that is a MonoBehaviour that wraps it:

public class GameData : MonoBehaviour
{
    public UserData User { get; set; }

    public static GameData Get() => FindObjectOfType<GameData>();
}

Say I have a class that tracks missions and once a mission is complete I double a user’s health:

public class MissionManager : MonoBehaviour
{
    private UserData _userData;

    private void Awake()
    {
        _userData = GameData.Get().User;
    }


    public void OnMissionComplete() {
        _userData.Health *= 2;
    }
}

The problem, is if I have other classes that access this User reference, the health can still be the original health if the reference is cached. The only way it works is to re-fetch the original: var userData = GameData.Get().User;. Is there a good way to fix this? Is the best approach just putting the UserData behind a singleton?

This is not how references work. UserData is a reference type, which means you have a reference to the actual object, not a copy. When you change the Health on your UserData, that change will be visible everywhere that UserData object is referenced from. “Caching” the reference does not create a copy that is independent of the original.

The only way you would see otherwise is if you were actually referencing two different UserData objects. Can you show your other code where you believe the change is not being reflected? Also please show real code if this is just pseudocode. The details are important.

There is no such thing as reference caching. At least not on a level you’re thinking about. As PraetorBlue said, if you’re having a fun time confusing yourself with what’s going on, then you’re certainly producing more independent instances than you’ve planned to. It’s not the end of the world for making such a mistake, however, it can be quite a pain to find what’s causing it, depending on how massive/clean your code base is.

Maybe by “caching” you mean “serializing”? Note that auto properties are never serialized, and private fields are not serialized by default (like in the code you’ve shown, first two boxes use auto properties, and the latter has a private field). And yes, deserializing objects does produce deep copies if that’s what you meant by “caching”. But you shouldn’t use this as a feature, this is quite unintended due to how serialization works, and so it’s normal to avoid this from happening, or at least be mindful about what is serialized and what is not. That said, if you want to preserve references during deserialization, you need to use SerializeReference attribute which is a relatively recent addition to the system.