LoginSignup
9
9

More than 1 year has passed since last update.

C#でデバッグ時のみ実行する処理を書く

Last updated at Posted at 2021-12-16

はじめに

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#が動く仕組みについて理解する良い機会になりました。
初学者の方は本記事に沿って単語を理解してみてはいかがでしょうか。

参考URL

C# プリプロセッサ ディレクティブ
#if DEBUG を使わないデバッグ分岐
属性

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9