読者です 読者をやめる 読者になる 読者になる

チリペヂィア

リンクフリー。サンプルコードなどは関連記事内でライセンスについて明示されない限り商用利用なども自由に行って構いませんが、自己責任でお願いします。またこれら日記内容の著作権自体は放棄していません。引用部分については引用元の権利に従ってください。

Disposeで簡単Destroy

コードが長くなってくるとやらかしやすい破棄漏れ(*1)。一時Texture2DとかMaterialとか、消しておかなきゃリークします。簡単なDispose()による対策をチラ裏。

abstract class OnDisposable : System.IDisposable
{
    public bool isDisposed { get { return m_disposed; } }

    public void Dispose()
    {
        this.DoDispose(true);
        System.GC.SuppressFinalize(this);
    }

    protected virtual void OnDispose() { }

    private void DoDispose(bool flag)
    {
        if (m_disposed == false) OnDispose();
        m_disposed = true;
    }

    ~OnDisposable()
    {
        this.DoDispose(false);
    }

    private bool m_disposed = false;
}

class ObjectDisposer : OnDisposable
{
    public ObjectDisposer(UnityEngine.Object obj) : this(new UnityEngine.Object[] { obj }) { }
    public ObjectDisposer(params UnityEngine.Object[] objects) { m_objects = objects; }
    protected override void OnDispose()
    {
        if (m_objects != null)
        {
            foreach (UnityEngine.Object obj in m_objects)
            {
                if (obj != null)
                {
                    if (Application.isEditor) DestroyImmediate(obj);
                    else Destroy(obj);
                }
            }
        }
    }
    private UnityEngine.Object[] m_objects;
}

使い方

Texture2D pxTex = new Texture2D(1, 1);
Texture2D subTex = null;
using (new ObjectDisposer(pxTex, subTex)) // まとめて登録
{
	if (条件とか) return; // returnやbreakしたって大丈夫。
	subTex = new Texture2D(128, 128);
	
	System.String text = null;
	text.ToString(); // 例外
}

usingのスコープカッコを抜ける時Dispose()経由でキッチリDestroy。例外をゲロさせてもDispose()経由でpxTexやsubTexは削除してもらえるのがusing構文のウマウマなとこ。

*1:そんな気にしなくても大丈夫だろと思ってたらやっぱりやってた…ネストの途中でreturnできないんですよね。ウッカリスコープ抜けちゃって末尾のDelete処理を飛ばして抜けるのは典型的ミスですが、弊害はそれに限らず、長い処理でreturnとかbreak的なネスト脱出法を採用できずフローが無駄に複雑化してスパゲティまっしぐらとか、時にはgoto文なんて頭をよぎって「いやいやさすがにソレは」とか。