Unityの環境別プログラミングに便利そうなConditionalAttributeを使ってみました。Editor上のみで使う関数、Androidのみで使う関数、といった記述をスマートに行えます。
参考:http://d.hatena.ne.jp/nakamura001/20151202/1449029637
長所1 プリプロセッサよりも可読性が高い
プリプロセッサを使ったサンプルコードと、ConditionalAttributeを使ったサンプルコードを比べてみましょう。まず、プリプロセッサを使った場合。
using UnityEngine;
public class TestPreprocessor : MonoBehaviour
{
void Start ()
{
#if UNITY_ANDROID
TestAndroid();
#endif
#if UNITY_WEBGL
TestWebgl();
#endif
#if UNITY_EDITOR
TestEditor();
#endif
}
#if UNITY_ANDROID
void TestAndroid()
{
Debug.Log("Android");
}
#endif
#if UNITY_WEBGL
void TestWebgl()
{
Debug.Log("WebGL");
}
#endif
#if UNITY_EDITOR
void TestEditor()
{
Debug.Log("Editor");
}
#endif
}
単純な記述なのでまだ読めます。しかし、長大な処理になると、終点のendifが見当たらないまま読むことになったりして快適さはかなり損なわれます。続いて、ConditionalAttributeを使った場合。
using UnityEngine;
public class TestConditional : MonoBehaviour
{
void Start ()
{
TestAndroid();
TestWebgl();
TestEditor();
}
[System.Diagnostics.Conditional("UNITY_ANDROID")]
void TestAndroid()
{
Debug.Log("Android");
}
[System.Diagnostics.Conditional("UNITY_WEBGL")]
void TestWebgl()
{
Debug.Log("WebGL");
}
[System.Diagnostics.Conditional("UNITY_EDITOR")]
void TestEditor()
{
Debug.Log("Editor");
}
}
かなりスッキリしたのではないでしょうか。呼び出し元に分岐条件を書く必要が無いので記述も楽です。ただ、分岐記述が無い分、特定環境下でしか呼ばれないことがわかりにくいので、ちょっとコメントを追加する必要があるかな、と思います。
長所2 プリプロセッサで引き起こされるコンパイルエラーが無い
Editorのみで使う関数をプリプロセッサで囲い忘れてコンパイルエラー、というのはプリプロセッサを使ってたら一度は遭遇すると思います。GitのメインブランチにMergeした後にCIツールがコンパイルエラーで動かなくなって気まずい思いをしたことが自分はあります。ConditionalAttributeでは前述のように呼び出し元については自動でSkipされるので、その心配はありません。
短所1 if not的な記述をできない
iOS以外、Editor以外、みたいな記述はできないようです。プリプロセッサはelse節があるので可能です。
参考: https://stackoverflow.com/questions/8230191/c-sharp-conditional-attribute
短所2 通常MethodとAttributeクラスにしか使えない
interfaceに対しては使えません。Constructor、Destructor、Operator、interface指定Methodにも使えません。interfaceに使えれば、Editor上でしか使わないinterfaceを用意して色々できそうだったのですが残念です。