VR、ゲーム制作、プログラミング。Unity とか Oculus Rift とか。

2013年8月8日木曜日

[Unity]null合体演算子でコンポーネントへのアクセスをスマートにする

C# の null 合体演算子 "??" が地味に便利です。

C/C++ はじめ、他の言語ではあまり見かけない、というか C# くらいにしか無さそうな演算子なのでなじみが薄い方も多いのではないかと思いますが、 ?? の左が null でなければ左、null なら右を返す演算子です。

??演算子 (C# リファレンス)

(2013/12/8 追記 : 型によって期待通り動かないことがあるかもしれません。具体的には UnityEngine.Animator がダメでした(弱参照にした場合はもちろん大丈夫でした)。参照型だと思うのですが…理由はまだ分かりませんが取り急ぎ。 /Unity 4.3)

Unity だとこんな感じで GetComponent() や Find() などの結果を高速化のためにキャッシュしておいたり、
private Hoge hoge_ = null;
void Func(){
    Hoge hoge = hoge_ ?? (hoge_ = GetComponent<hoge>());
    hoge.DoSomething();
}

子オブジェクトのコンポーネントへの getter を提供したり、
System.WeakReference piyo_ = new System.WeakReference(null);
public Piyo piyo {
    get { return (piyo_.Target ?? (piyo_.Target = transform.GetComponentInChildren<Piyo>())) as Piyo; }
}

あるコンポーネントが付加されていなかったら追加しつつ取得する拡張メソッドを書いたりと、地味ながらよく使う処理をスマートに書けます。
public static class GameObjectExtentions
{
    public static Component ExAttachComponent(this GameObject gameObject, string type)
    {
        if(!gameObject){ return null; }
        return gameObject.GetComponent(type) ?? gameObject.AddComponent(type);
    }
    
    public static T ExAttachComponent<T>(this GameObject gameObject)
        where T : Component
    {
        if(!gameObject){ return null; }
        return gameObject.GetComponent<T>() ?? gameObject.AddComponent<T>();
    }
}

三項演算子でももちろん書けますが、冗長になりがちですね。
// GetComponent() が null でなくても 2 回呼ばれる(はず。最適化してくれるんだろうか?)
//return gameObject.GetComponent<Hoge>() ? gameObject.GetComponent<Hoge>() : gameObject.AddComponent<Hoge>();

Component component = gameObject.GetComponent<Hoge>();
return component ? component : gameObject.AddComponent<Hoge>();

以上、なくても困らないけどあると便利な null 合体演算子でした。


2013/12/8 追記 : UnityEngine.Animator で正しく動かないことを追記しました。

0 件のコメント:

コメントを投稿