Why Access Singleton Class via Instance in Unity

Why Access Singleton Class via Instance in Unity

In C# or Unity, when creating a Singleton class, we typically choose between two approaches:

  • One is to expose the Instance publicly so you access it via Manager.Instance.SomeFunction().
  • The other is to hide the Instance and wrap the variable or function in a static property, so you access it directly with Manager.SomeFunction().

Both methods work in practice, but in the long term, using the Instance explicitly is much better.

Exposing the Instance

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    public void StartGame() { }
}

Usage:

GameManager.Instance.StartGame();

You always access it via the Instance.

Hiding the Instance and Wrapping in Static

public class GameData : MonoBehaviour
{
    private static GameData _instance;

    public static bool IsGameStarted
    {
        get { return _instance.isGameStarted; }
    }

    private bool isGameStarted;
}

Usage:

if (GameData.IsGameStarted)
{
    // process
}

It looks like you are accessing it statically.

Why Not Just Use Static?

Honestly, it's possible. Many codes use this static wrapping approach.

However, over time, problems start to arise:

It Looks Static but Internally Uses Instance

Even if you wrap the property in static, inside, it still references the _instance.

This _instance depends on Unity objects. If, during scene transitions or in cases where you manually call Destroy() or Play/Stop in the editor, the object is destroyed, Instance becomes null, and trying to access it as if it's static will lead to a crash.

Unity's Lifecycle Doesn't Match Static Wrapping

Unity dynamically creates and destroys objects, but static variables stay in memory throughout the program.

If you're still holding onto a static pointer for a destroyed object, it will cause runtime errors and even memory leaks.

It Doesn't Align with Singleton Philosophy

Singleton is a pattern for managing "one living object." The object needs to exist, and we should be able to ensure it's alive when needed and possibly destroyed at the right time.

Static wrapping ignores the lifecycle of the object and messes with the core design intention of a Singleton.

Difference from Static-Only Classes

Here's a key distinction.

For example, Unity's Mathf class is a collection of static functions that don't need to hold state:

float clamped = Mathf.Clamp(value, min, max);

Mathf doesn't store any values. It doesn't remember past calculations. It simply calculates and returns the result based on the input parameters.

Such classes don't need an object instance, so static is the correct approach.

On the other hand, GameManager or GameData classes:

  • Need to store game state
  • Manage events
  • Behave like living objects

So, handling living objects as static-wrapped properties is fundamentally different from static-only classes like Mathf.

Summary

Although it's easier to use static wrapping, you should always access Singleton classes through Instance.

Doing so ensures that you are always conscious of whether the object is alive, allows you to naturally synchronize with Unity's lifecycle, and maintains the integrity of the "living object" concept that Singleton is meant to manage.

Classes like GameManager or data storage managers should expose their Instance to reveal the design intention clearly.

In the end, accessing through Instance isn't just about dealing with the inconvenience of extra typing—it's about ensuring code consistency and system stability.

Popular posts from this blog

Understanding Arrays as Reference Types in C#

Setting Up a Basic Follow Camera with Cinemachine 3.x

How to Initialize Struct – C# Struct Initialization Guide