C#でもC++のように以下のプロプロセッサが利用可能です。
コードを折り畳む #region, #endregion
シンボルの定義 #define
シンボルを未定義にする #undef
コンパイル時警告出力 #warning
コンパイル時エラー出力 #error
行番号とファイル名の設定 #line
条件付コンパイル #if, #else, #elif, #endif
#region 〜 #endregion で囲んだ範囲のソースコードを
VisualStudio .NETのアウトライン機能を使って
展開したり折り畳んで省略表示することができるようになります。
ソースコードは縦方向に長く伸びるものなので
適当な位置に当該プリプロセッサを挿入することで
ソースコードの見通しが良くなります。
【書式】
#region 名前(任意です)
中略
#endregion
#regionの後の名前は任意で付けることができますが(省略可能)
折り畳んだ際に、どんなコードを折り畳んだのかが視覚的にわかるように
名前を付けることをおすすめします。
【補足1】
注意点として、折り畳んだ状態のソースコードは
検索時、検索対象からはずれます。
(検索ダイアログにて非表示部分も検索するよう指定すれば検索対象になります)
また、実用的な利用場面としては
・コントロールの作成、プロパティ設定などの初期処理を囲む
(単調なコードが連続するので隠す)
・クラスのメンバ変数宣言部分を囲んで隠す
・デバッグ版などの特定ビルドでのみ実行される部分のコードを囲む
などが挙げられます。
用途は自由です。お好みで。
【補足2】
#regionブロックは、以下のように#ifブロックを跨いで利用できません。
(オーバーラップ不可)
┌─#region
│ 中略
┌┼─#if TAKO
││ 中略
│└─#endregion
│ 中略
└──#endif
後述する #if 等で利用されるシンボルを定義します。
定義されたシンボルは、コンパイルの制御に使われます。
【書式】
#define シンボル
【補足】
C,C++のように、テキスト置換やマクロ関数作成目的で利用することはできません。
C#では#defineの役割はシンボルを定義することのみです。
なお、同様のことが
/defineコンパイラオプションで実現可能です。
前述の#defineで定義されたシンボルを未定義にします。
利用することで、より細かいコンパイル制御ができます。
【書式】
#undef シンボル
【例】
#define TEST
#if TEST
// この箇所のコードはコンパイルされます。
#endif
#undef TEST
#if TEST
// この箇所のコードはコンパイルされません。
#endif
コンパイル時に警告メッセージを出力します。
単なる警告なのでコンパイルは続行されます。
メッセージは日本語でも構いませんし
""で囲む必要もありません。
用途としては
コードのどの部分がコンパイルされているのか、確認用などに。
(特にifディレクティブでコンパイル箇所が条件分岐する箇所などで)
【書式】
#warning 警告メッセージ
コンパイル時にエラーメッセージを出力します。
コンパイルエラーとなります。
メッセージは日本語でも構いませんし
""で囲む必要もありません。
単体でも利用可能ですがあまり意味はありません。
後述する条件付コンパイル用プリプロセッサと組み合わせて
ある条件下でコンパイルエラーを発生させ
コンパイルを停止させる用途で利用します。
【書式】
#error エラーメッセージ
【例】
#if TEST
中略
#else
// 期待していたシンボルが未定義なのでエラーとする
#error TESTシンボル未定義
#endif
コンパイル時に出力される
エラーや警告メッセージの行番号とファイル名を指定します。
【書式1】
行番号とファイル名(省略化)を指定します。
その具体的な利用シーンや効果など、まだ私自身不明です。
#line 行番号 ファイル名
【書式2】
別の#lineディレクティブが見つかるまで
これ以後のコードをデバッガから隠します。
#line hidden
【書式3】
ファイルの行番号指定を元に戻します。
#line default
【例】
下記例のコードをデバッガで実行すると
2を出力している行は無視されます。
無視とは、ブレークポイントを設定できず、
また、ステップ実行してもデバッガはその行を無視して次へ進みます。
しかしながら、デバッガが無視するだけで
実際には2の文字は出力されます。
static void Main(string[] args)
{
Console.WriteLine("1");
#line hidden // これ以後をデバッガから隠す
Console.WriteLine("2"); // デバッガ実行時、無視されます
#line default // hiddenより復帰し、隠さないようにする
Console.WriteLine("3");
}
1つ、または複数のシンボルが定義されているか否か評価され、
条件を満たすコードだけをコンパイルすることができます。
書き方はif文と似ています。
シンボルが定義されていれば、そのシンボルはtrueと評価され、
逆に定義されていなければ、falseと評価されます。
【書式1】
1つのシンボルが定義されている場合コンパイル
#if シンボル名
シンボル名が定義されていれば
#if〜#endif間のコードがコンパイルされます。
#endif
【書式2】
複数のシンボルが定義されている場合コンパイル
複数のシンボルを評価するために以下の演算子を利用できます。
== 等しい
!= 等しくない
&& AND
|| OR
さらに、()を使ってシンボルと演算子をグループ化可能です。
(下記例の場合、()は不要ですが)
#if (シンボル名1 && シンボル名2)
シンボル名1とシンボル名2が定義されていれば
#if〜#endif間のコードがコンパイルされます。
#endif
【書式3】
#ifの条件を満たさなかった場合、#else〜#endif間のコードをコンパイル
#if シンボル名
シンボル名が定義されていれば
#if〜#else間のコードがコンパイルされます。
#else
シンボル名が定義されていなければ
#else〜#endif間のコードがコンパイルされます。
#endif
【書式4】
いずれかのシンボルが定義されている場合コンパイル
#if シンボル名1 || シンボル名2
シンボル名1 または シンボル名2 のいずれかが定義されていれば
#if〜#endif間のコードがコンパイルされます。
#endif
【書式5】
最初の条件が満たされなかった場合、次の条件が評価されます。
#if シンボル名1
シンボル名1が定義されていれば
#if〜#elif間のコードがコンパイルされます。
#elif シンボル名2
シンボル名1が定義されておらず
シンボル名2が定義されていれば
#elif〜#else間のコードがコンパイルされます。
#else
シンボル名1,2いずれも定義されていなければ
#else〜#endoif間のコードがコンパイルされます。
#endif
【書式6】
シンボルの代わりにtrue,falseを使用することができます。
#if false
この部分のコードがコンパイルされることはありません。
コメントアウト。
#endif
【書式7】
シンボルの前に!を付けて、
そのシンボルが定義されていない場合のみコンパイル
#if !シンボル名
シンボル名が定義されていなければ
#if〜#endif間のコードがコンパイルされます。
#endif