はじめに
C#でローカル環境だけで動かしたい処理がありました。
調べてみると、プリプロセッサディレクティブを使って#if DEBUG
のように記述すると、[Conditional("DEBUG")]
のように記述して属性を付与する二つの書き方があることがわかりました。
初学者向けに単語の説明も交えながら簡単にまとめてみました。
プリプロセッサディレクティブ使うやり方を方法1、属性を付与するやり方を方法2としています。
目次
方法1(プリプロセッサディレクティブ)
方法2(属性)
まとめ
方法1(プリプロセッサディレクティブ)
基本的な書き方
public void TestMethod()
{
#if DEBUG
Console.WriteLine("デバッグ時に実行");
#else
Console.WriteLine("デバッグ以外で実行");
#endif
}
解説
プリプロセッサディレクティブを使用して、#if
、#else
、#endif
をシンボルの定義に基づいて条件付きコンパイルを制御しています。ざっくり用語の解説をします。
プリプロセッサディレクティブ
-
#if
、#else
、#endif
の部分 - コンパイルの前に行う処理のこと
シンボル
-
DEBUG
の部分 -
#if
などの後ろに記述する - コンパイル時に生成するIL(中間言語)を切り分けるのにプリプロセッサディレクティブと組み合わせて使われる
- コンパイルするコマンドのオプションでシンボルを定義できる
-
DEBUG
はビルド構成プロパティのデバッグモードやリリースモードで自動的に指定できる
条件付きコンパイル
次の 4 つのプリプロセッサ ディレクティブを使用して、条件付きコンパイルを制御します。
-
#if
条件付きコンパイルを開く。コードは、指定されたシンボルが定義されている場合にのみコンパイルされる。 -
#elif
前の条件付きコンパイルを閉じ、指定されたシンボルが定義されている場合、新しい条件付きコンパイルを開く。 -
#else
前の条件付きコンパイルを閉じ、前に指定されたシンボルが定義されていない場合、新しい条件付きコンパイルを開く。 -
#endif
前の条件付きコンパイルを閉じる。
仕組みとしては、C# コンパイラが、#if
ディレクティブ、次いで #endif
ディレクティブが検出すると、条件で指定されているシンボルが定義されている場合に、ディレクティブ間のコードがコンパイルされます。
簡単に例をあげると、DEBUG
でシンボルを定義してコンパイルすると#if DEBUG
以降の処理が実行されます。
実用的な書き方
以下のような発展的させた実用的な書き方がありました。
internal static class AssemblyState
{
public const bool IsDebug =
#if DEBUG
true;
#else
false;
#endif
}
public void Foo()
{
if(AssemblyState.IsDebug)
{
Console.WriteLine("デバッグ時に実行");
}
else
{
Console.WriteLine("デバッグ以外で実行");
}
}
解説
プリプロセッサディレクティブをまとめて書くために1つクラスを用意しています。
それにより、分岐したい部分が複数あっても、#if
を書くのは一ヵ所で済みます。
メリット
実行時に分岐処理が発生せず、処理速度が落ちない。
実行時に分岐が定数の場合はJITコンパイラコンパイル時に不要な#if
と分岐を削除し、機械語レベルで最初のコードと同じになります。つまり、IL には分岐が存在するが、機械語には分岐がないため実行速度も落ちません。
方法2(属性)
記述例
[Conditional("DEBUG")]
public static void ShowMessage(string str)
{
Console.WriteLine(str);
}
※Attributeを省略してConditionalでも記述可能
解説
- 属性(attribute)
- クラスやメンバに追加情報を与える
- DEBUGがシンボルで定義されている時のみ有効となる
メリット
- コード量が少なくてすむ
デメリット
- 使用できる場面が限られている
クラスか戻り値のないメソッドに使えるが、戻り値のあるメソッドには使えない。
まとめ
デバッグのみで動かしたい処理が複数箇所ある場合は方法1の実用的な書き方が使いやすいです。
戻り値のないメソッドの場合は方法2がコード量が少なくて見やすいのでおすすめです。
また、個人的にこの記事を作成するにあたってC#が動く仕組みについて理解する良い機会になりました。
初学者の方は本記事に沿って単語を理解してみてはいかがでしょうか。