【Unity】 UnityEditorの時のみDebug.Logを出す方法

# はじめに

デバッグ時に書いた`Debug.Log`を忘れて放置してしまい、ビルド後もログを吐き続けさせてしまった経験はありませんか？
ビルド設定をOFFればビルド後の`log.txt`への吐き出しを止めることはできます。が、それでも`Debug.Log`は実行されてしまうのでその分の実行コストが無駄になってしまいます。

今回は、この`Debug.Log`をUnityEditor上で作業している時のみ動作させるようにしてみます。

# 先に結論を書くと

**#if/#endifよりもConditional属性を使おう**

* #id/#endifで実行のon/offはできるがメソッドの呼び出しコストは健在なので無駄が残る
* メソッドにConditional属性をつけることで、コンパイラがメソッド呼び出しそのものをスキップするようにしてくれるようになる

# 解説
## 下準備

`Debug.Log`を直接呼ばず、ラップして呼び出す形にします。

```csharp:DebugLogger
public static class DebugLogger
{
    public static void Log(object o)
    {
        UnityEngine.Debug.Log(o);
    }
}
```

```csharp:呼び出し方
DebugLogger.Log("This is log text.");
```

## 方法1: #ifと#endifを使う

\#ifと\#endifを使うことで、特定の条件の時のみ対象のコードブロックをコンパイルするように指定することができます。  
これを用いて、`UNITY_EDITOR`のDefineが存在するときのみ`Debug.Log`を実行するようにします。

```csharp:DebugLoggerのDebug.Log呼び出し部分を書き換える
public static class DebugLogger
{
    public static void Log(object o)
    {
#if UNITY_EDITOR
        UnityEngine.Debug.Log(o);
#endif
    }
}
```

こうすることで、`DebugLogger.Log`をビルド後に呼び出したとしても、`Debug.Log`のブロックが実行されないためログが吐き出されることはありません。ですが、この方法ではDebugLogger.Logの呼び出しコストが残ったままになってしまい、結局`Debug.Log`を直接呼び出してるのとそんなに変わりません。

ではその対策としてメソッドごと#ifブロックで包んだとしても、今度はビルド時に未定義扱いになりビルドエラーが発生してしまい上手く行きません。

```csharp:(ダメな例)この書き方をするとビルド時にエラーになる
public static class DebugLogger
{
#if UNITY_EDITOR
    //ビルド時にこのLogメソッドが未定義扱いになり呼び出し箇所があるとビルドエラーになる
    public static void Log(object o)
    {
        UnityEngine.Debug.Log(o);
    }
#endif
}

```

## 方法2:Conditional属性を使う

別の方法として、[Conditional属性](https://msdn.microsoft.com/ja-jp/library/4xssyw96(v=vs.90).aspx)を使う方法があります。
Conditional属性でメソッドをマークすることで、対象のDefineが定義されている場合のみメソッドが実行されるようにコンパイラが処理してくれるようになります。

```csharp:Conditional属性を用いてUNITY_EDITORの時のみ実行を許可する
using System.Diagnostics;

public static class DebugLogger
{
    [Conditional("UNITY_EDITOR")]
    public static void Log(object o)
    {
        UnityEngine.Debug.Log(o);
    }
}
```

```csharp:呼び出し方は変わらず
DebugLogger.Log("This is log text.");
```

Conditional属性を使うことで、メソッド定義は残したままにできるのでビルド時にエラーになることはありません。また、コンパイラがメソッドの呼び出しをスキップするようにビルドしてくれるため、メソッドの呼び出しコストもなくすことができます。


# まとめ

メソッドの中身をまるごと#ifで包んでいた人は、Conditional属性を使う方法に書き換えることをオススメします。

#おまけ

[LiveConsole](https://www.assetstore.unity3d.com/jp/#!/content/14563)ってAssetがログを色付けしてくれて見やすかったので、色付きでログ吐く拡張メソッドを生やしてみました。

```csharp
using System.Diagnostics;
using Debug = UnityEngine.Debug;

namespace Hogehoge
{
    public static class ForLogExtensions
    {
        [Conditional("UNITY_EDITOR")]
        public static void Red(this object t,string tabMessage = "Red")
        {
            Debug.Log(string.Format("[{0}:r]{1}",tabMessage, t));
        }

        [Conditional("UNITY_EDITOR")]
        public static void Green(this object t, string tabMessage = "Green")
        {
            Debug.Log(string.Format("[{0}:g]{1}", tabMessage, t));
        }

        [Conditional("UNITY_EDITOR")]
        public static void Cyan(this object t, string tabMessage = "Cyan")
        {
            Debug.Log(string.Format("[{0}:c]{1}", tabMessage, t));
        }

        [Conditional("UNITY_EDITOR")]
        public static void Yellow(this object t, string tabMessage = "Yellow")
        {
            Debug.Log(string.Format("[{0}:y]{1}", tabMessage, t));
        }

        [Conditional("UNITY_EDITOR")]
        public static void Orange(this object t, string tabMessage = "Orange")
        {
            Debug.Log(string.Format("[{0}:o]{1}", tabMessage, t));
        }

        [Conditional("UNITY_EDITOR")]
        public static void Magenta(this object t, string tabMessage = "Magenta")
        {
            Debug.Log(string.Format("[{0}:m]{1}", tabMessage, t));
        }

        [Conditional("UNITY_EDITOR")]
        public static void Blue(this object t, string tabMessage = "Blue")
        {
            Debug.Log(string.Format("[{0}:b]{1}", tabMessage, t));
        }
    }
}
```

```csharp:使い方
//拡張メソッドを呼ぶだけ
void Update()
{
    transform.position.Red("Position");
    transform.rotation.Blue("Rotation");
}
```

![Console](https://qiita-image-store.s3.amazonaws.com/0/47146/9eb8c419-66d6-1452-609b-7692dd7d70ef.png)


拡張メソッドでログ吐けるようにするの、結構便利なのでオススメです。  
~~ただIntelliSenseが汚染されるけどね~~
![IntelliSense](https://qiita-image-store.s3.amazonaws.com/0/47146/4cb5596c-5643-cd73-9ad3-ca69e191dd6c.png)