はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】#ifディレクティブとConditional属性について

はじめに

もしUnityを扱ったことのある方は以下のようなコードをみたことはないでしょうか。

#if UNITY_EDITOR
  Debug.Log("Unity Editor");
#endif

#if ~ #endifの中にあるDebug.LogはUnityのエディタのときのみコンパイル,実行されます。

これらは別にUnity特有の機能というわけではなく、C#の機能です。

今回はこの#ifについて取り上げていきたいと思います。

#ifディレクティブ

冒頭でも述べましたが、#if#endifの両ディレクティブで囲まれたコードの条件付きコンパイルが行えます。

書き方としては、#ifディレクティブの後ろのシンボル式を書きます。

#define SAMPLE1
// #define SAMPLE2

using System;

class Program
{
    static void Main(string[] args)
    {
#if SAMPLE1
        Console.WriteLine("こっちはコンパイルされる");
#endif
#if SAMPLE2
        Console.WriteLine("こっちはコンパイルされない");
#endif
    }
}

また演算子を使った書き方もできます。

#define SAMPLE1
// #define SAMPLE2

using System;

class Program
{
    static void Main(string[] args)
    {
#if SAMPLE1 || SAMPLE2
        Console.WriteLine("こっちはコンパイルされる");
#endif
#if SAMPLE1 != SAMPLE2
        Console.WriteLine("こっちはコンパイルされる");
#endif
#if !SAMPLE1
        Console.WriteLine("こっちはコンパイルされない");
#endif
#if SAMPLE1 && SAMPLE2
        Console.WriteLine("こっちはコンパイルされない");
#endif
    }
}

Conditional属性

#ifの場合、たくさんの箇所に使うのはなかなか骨が折れます。

そういった問題を軽減するためにConditional属性を使うことで条件付きメソッドを作成することができます。

#define DEBUG

public static class Debug
{
    [Conditional("DEBUG")]
    public static void Log(string message)
        => Console.WriteLine(message);
}

もしデバック用の出力をDebug.Logで活用するように徹底していれば、簡単に出力を実行するかしないか決めることができます。

ただし一番の落とし穴は条件付きメソッド自体は常にコンパイルされ、呼び出し部分のみコンパイルされない仕組みになっていることです。

つまり#ifの代用として使えますが、少し性質が異なること(例えばファイルのサイズが増える等)に注意してください。

さいごに

UnityでもDebug.Logをリリースビルドに含めてしまうのを防ぐためにどうすれば良いかという議論がよくあります。

そもそも UnityDebug.Logが重いのはスタックトレースに時間がかかっているからであり,Project Settingにて変更ができたはずなので今回紹介したものはさほど必要ないかもしれません。

ただ色々な場面で利用できるので、覚えておいても損はないと思います。

是非うまく活用してみてください。

ではまた。