In Unity3D having a singleton class is very useful, whether for "global" state or simply for the convenience of having a static accessor so you don't have to have lots of: FindObjectOfType(typeof(Builder)) as Builder;
So you code up a C# singleton and then realize that you actually need it to be a MonoBehavior, not just a ScriptableObject -- say you want the singleton to run coroutines, or have a transform, or any other MonoBehavior feature. But monobehaviors can't be initialized with a constructor.
So what you want is a monobehavior pseudo singleton pattern. The unity community wiki has some good info about the various options but all require boilerplate.
So I wrote a parametrized generic pseudo singleton monobehavior class. I attempted to compile all the best advice out there, so it is threadsafe, has some extra stuff for setting a parent, doesn't implement an Awake, and initializes lazily.
The key was the C# where keyword, used to constrain the parameterizing type. So in this case both the class is a MonoBehavior and its parameterization type is a MonoBehavior.
So now this blog has its first code section:
using UnityEngine;
using System.Collections;
///
/// MONOBEHAVIOR PSEUDO SINGLETON ABSTRACT CLASS
/// usage : best is to be attached to a gameobject but if not that is ok,
/// : this will create one on first access
/// example : '''public sealed class MyClass : Singleton {'''
/// references : http://tinyurl.com/d498g8c
/// : http://tinyurl.com/cc73a9h
/// : http://unifycommunity.com/wiki/index.php?title=Singleton
///
public abstract class Singleton : MonoBehaviour where T : MonoBehaviour
{
private static T _instance = null;
///
/// gets the instance of this Singleton
/// use this for all instance calls:
/// MyClass.Instance.MyMethod();
/// or make your public methods static
/// and have them use Instance
///
public static T Instance {
get {
if (_instance == null) {
_instance = (T)FindObjectOfType (typeof(T));
if (_instance == null) {
string goName = typeof(T).ToString ();
GameObject go = GameObject.Find (goName);
if (go == null) {
go = new GameObject ();
go.name = goName;
}
_instance = go.AddComponent ();
}
}
return _instance;
}
}
///
/// for garbage collection
///
public virtual void OnApplicationQuit ()
{
// release reference on exit
_instance = null;
}
// in your child class you can implement Awake()
// and add any initialization code you want such as
// DontDestroyOnLoad(go);
// if you want this to persist across loads
// or if you want to set a parent object with SetParent()
///
/// parent this to another gameobject by string
/// call from Awake if you so desire
///
protected void SetParent (string parentGOName)
{
if (parentGOName != null) {
GameObject parentGO = GameObject.Find (parentGOName);
if (parentGO == null) {
parentGO = new GameObject ();
parentGO.name = parentGOName;
}
this.transform.parent = parentGO.transform;
}
}
}
Full gist is here.