Workaround to make static field exposed in Editor

Hello,

I’ve read a few threads about this, but can’t wrap my mind around it…
I have a class ‘Web’ attached to a GameObject. This class has 2 fields I want to expose in the Editor:

[SerializeField]
private string _clientId;
[SerializeField]
private string _projectId;

Since these fields should exist only once, it’d feel logic to make them static. But you apparently can’t expose static fields in the Editor. I’ve read that maybe the workaround is to use a singleton, but I’m not familiar with that and I’m obviously doing it wrong.

This is what I do:

public class Web : MonoBehaviour
{
    [SerializeField]
    private string _clientId;
    [SerializeField]
    private string _projectId;

    private string clientId, projectId;
    private static Web _instance;

    private Web()
    {
        clientId = _clientId;
        projectId = _projectId;
    }

    public string GetClientId()
    {
        Debug.Log("clientId is " + _instance._clientId);
        return _instance._clientId;
    }

    public string GetProjectId()
    {
        return _instance._projectId;
    }

    public static Web GetInstance()
    {
        return _instance;
    }

    void Start()
    {
        _instance = new Web();
    }
}

But the debugger shows me that doing that gives me a ‘null’ value for ‘_instance’.

  • Why is that?

  • What would be the correct way to achieve what I want?

  • Is it ‘ok’ (i.e. good practice) to use singletons in scripts/classes that are attached to GameObject? (I have to say I’m a bit confused between the ‘_instance’ and the object obtained via ‘GameObject.GetComponent’…)

  • Should I forget about this idea of using singleton and simply accept that I’ll need to access _clientId and _projectId via something like

GameObject.Find("MyGameObject").GetComponent<Web>()._clientId;

(would that be the best practice) ?

Thanks a lot!!
Arnaud

You can’t new() MonoBehaviour objects like that. You would be achieving the correctish thing by just changing your Start() to:

void Start() {
    _instance = this;
}

Though Awake() is usually used instead of Start for this, as it runs earlier, so other objects can access the data in their Start() methods.

There are a bunch of downsides to this (you have to put exactly one copy of the script in every scene, the data isn’t ready in other object’s Awake).

Is this just global configuration data that you need to always have available? In that case a good way to have it ready is to stick the data in a ScriptableObject singleton instead, and then load that either through Resources or Addressables in a [RuntimeInitializeOnLoad] method.

Thank you for your reply, I’ll give that a try!

It’s global configuration data indeed, that I need always available. It is used in that class, but not only there, so I guess there’s no real reason to have it in that class in particular. I like the idea of the ScriptableObject (don’t know about RuntimeInitializeOnLoad, but I’ll look it up :slight_smile: )!

Thanks again!