サークル獏の佐藤敏 Unityとか備忘録

サークル獏の佐藤敏がUnityとかで知ったTipsを書いておく備忘録です。

【教えてください】UnityでMonoBehaviorでないSingletonはどうやる?

Singletonでいこう

世間ではUniRxやらZenjectでSingleton祭りを脱却しよう、みたいな記事がたくさん出ている。
だが、小規模アマチュア僕たちはSingleton祭りでいいんじゃないかなという気がしてしまう。
どうせゲームのTestは書きづらいということもあるし。
 

MonoBehaviorのSingletonは既に色々説明記事がある

qiita.com
tsubakit1.hateblo.jp

このようにMonoBehaviorのSingletonは既に色々説明記事がある。
が、「別にMonoBehaviorの機能いらないよ」という場合はコレで実装するのがどうも気が引ける。
MonoBehaviorに生えているプロパティやらメソッドの数は結構なものであるし、インテリセンスで余計なものがサジェストに大量に出てくるのも微妙だ。
 

MonoBehaviorでないSingletonを書く

MonoBehaviorでないSingleton実装方法としては、普通はこんな感じだろうか。
(非常にSingletonにされやすい音関係をイメージしてクラス名はSoundManagerとした)

public class SoundManager
{
    private static SoundManager mInstance = null;
    public static SoundManager Instance
    {
        get {
            if (mInstance == null) {
                mInstance = new SoundManager();
            }
            return mInstance;
        }
    }

    //privateなので var s = new SoundManager(); とかはできない
    private SoundManager() {

    }

    public void Play(string key) {
         ...
    }

これで、

SoundManager.Instance.Play("bang");

とか

var SoundManager soundManager = SoundManager.Instance;
soundManager.Play("bong");

とかすればフツーに使える。

f:id:VinSatoo:20180926171249p:plain
newもできないのでたしかにSingletonとして機能している。
 

うまくいかない、SingletonBaseを継承するパターン

が、毎度毎度mInstanceのどうこうを書くのは非常にめんどい。
SingletonBaseとかを継承すればOKという風にしたい。

public class SoundManager : SingletonBase<SoundManager>
{
    private SoundManager() {

    }

    public void Play(string key) {
         ...
    }

とかできれば非常にラクで見やすい。
ところが、

public abstract class SingletonBase<T>
    where T : SingletonBase<T>, new()
{
    private static T mInstance = new T();
    public static T Instance
    {
        get {
            return mInstance;
        }
    }
}

のように書いて継承するとエラーが起きてしまう。
f:id:VinSatoo:20180926171552p:plain
(パブリックでないとダメだそうだ……)
 
 
f:id:VinSatoo:20180926171738p:plain
SoundManagerコンストラクタをpublicにすればエラーはでないが……
その場合、
f:id:VinSatoo:20180926171811p:plain
普通にnewできてしまう。
これではSingletonではない。

教えてください

ぶっちゃけ1人で書いている場合は「newしないように気をつける」「全部staticプロパティやメソッドにするよりは見やすくて書きやすいからメリットあり」ってことでコンストラクタをpublicにしたまま上記のSingletonBaseを使っていってもいいのだが、やはり気持ち悪い。

どうすればこのケースでコンストラクタをpublicにせずSingletonBaseクラスを書けるか、C#に詳しい人教えてくださいm(__)m