プリプロセッサというものをご存じだろうか。
#regionなんかは、変数を綺麗にまとめられる、ということで知っている人もいるかもしれないが、簡単に言うとそういった#~と始まる物たちのことだ。
環境:Visual Studio 2019、Unity 2020
きっかけ
たまたまC# の本を眺めてた際に、#if、#elseなんて文字を見つけた。
・・・ifじゃないのん?#ってなんやねん!!
ってことで調べてみたところ、記事が少なかったように感じたので、同じく疑問に思った人も使えるようにと思い書いてみた。
プリプロセッサとは
では、プリプロセッサとは何か。
プリプロセッサと調べてみると、以下のような説明が出てきたが、正直小難しくて何言ってるかわからん!!ってなる人は、コンパイルよりも前に行われる、コードのデバッグや可読性が向上する程度に覚えておいてもらえればいいと思う。
条件付きコンパイルや、VS.NETでの表示領域の制御などを処理するプリプロセッサ。 ... プリプロセッサは、ソース・コードをコンパイルする前に、前処理を行う機能である。 これにより、ソース・コードでは表現しがたい多くの便利な機能が実現されている。 例えば、テストやデバッグ時には便利な、条件付きコンパイルなどが利用できる
https://www.atmarkit.co.jp/ait/articles/0301/08/news002.html
で、結局どんなことが出来るのか。
要はデバッグ時のコードはこっち、本番ではこっちのコードを使う~っといったようにコードを状況によって使い分けることが出来るのだ。
#define
#defineはシンボルを定義する。
まあ、シンボルってなんぞや。定義?って感じだと思うが、簡単に言ってしまえばプリプロセッサで使う用の変数みたいなものという認識でいいと思う。
これ自体に意味はなく、後で使う#ifや#elseなんかと組み合わせて使う。
#defineを使うときは以下のように書く。
//このように先頭に定義する。
#define Test1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//ーーーーー 略 ーーーーーー
usingよりも上、つまりコードの一番上で定義しなくちゃいけないのが注意。
※以降、定義した物をシンボルと記述しています(上のコードだとTest1のこと)。
#undef
シンボルをソースコード上で無効にする。
これも#define同様、コードの先頭で定義しなければいけない。
#undefを使うときは以下のように書く。
//このように先頭に定義する。
#undef Test1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//ーーーーー 略 ーーーーーー
#ifシリーズ
これは通常のif文と同じだ。
シンボルの有無によってコンパイルする部分を指定することが出来る。
#if、#elif、#else、#endifの4つがあり、それぞれ以下のような内容になっている。
#if・・・通常のif文と同じくシンボルがあるか確認する。||や&&も使える。
#elif・・・else ifと同じ。ifが違った場合にさらに条件分岐したい場合に使う。
#else・・・通常のelseと同じ。ifの条件が違った場合に入る。
#endif・・・if文がここまでですよーという宣言。これが無ければエラーになる。
例
#define TEST
#define AA
#define BB
using UnityEngine;
public class Test : MonoBehaviour
{
void Start()
{
#if TEST//TESTがあるかどうか
//ここに入る
#elif GG//else ifと同じ
//ここには入らない。
#else//elseと同じ
//ここには入らない。
#endif//if文がここまでという宣言。
}
}
#region
最初でも少し触れたが、#regionを使用すると、コードの領域分けが出来る。
領域分けってなんぞや?って人のために簡単に説明すると、メソッドなんかを閉じたり開いたりできる-を自分で好きな位置に作れるということだ。
(説明下手ですみません・・・)
使い方は簡単で、#regionで開始位置を指定して、#endregionで終了する。
例
#region
int a;
int b;
int c;
#endregion
int d;
int e;
//↓
//こんな感じに閉じることが出来る。
#region
int d;
int e;
Conditional属性
Conditional属性は、メソッドをコンパイルするかどうかを指定することが出来る。
簡単に言ってしまうと、処理は#ifで分けてたのに対して、メソッドはConditional属性を書くだけで実行するかどうか指定できる。
又、Conditional属性を使用する際には、以下のような条件がある。
・using System.Diagnostics;が存在する。
・戻り値がvoidであること
・オーバーライドしていないこと。
例
#define TEST
//必要
using System.Diagnostics;
public class Test
{
[Conditional("TEST")]
void TES()
{
//TESTが存在する際に実行される処理
}
//戻り値がvoidじゃない為、エラーになる
[Conditional("TEST")]
int TESInt()
{
}
}
最後に(Unityでの使用)
以上がだいたいのC#におけるプリプロセッサだ。
プリプロセッサはデバッグなどにおいては、非常に使い勝手がいいので徐々に開発にも取り入れていきたい。
又、実はUnityにはあらかじめ幾つかのシンボルが定義されており、buildやeditorでのコードのコンパイル分けなどが出来るようになっている。
Unityのシンボル一覧
https://docs.unity3d.com/ja/2018.4/Manual/PlatformDependentCompilation.html
以下参考にさせていただいたサイト様
https://programming.pc-note.net/csharp/preprocess.html
↧