C# Tips
−条件付きコンパイル(ConditionalAttribute)−


[トップ] [目次]

条件付きコンパイル

C#には、C++と同じように#if、#endifなんかもありますが、もっとモダンな方法も用意されています。
それがSystem.Diagnostics.ConditionalAttributeクラスです。


using System;
using System.Diagnostics;

public class Test {
    [Conditional("TEST")]
    public void Func1() {
        Console.WriteLine("Func1");
    }
    
    [Conditional("CHECK")]
    public void Func2() {
        Console.WriteLine("Func2");
    }
    
    public static void Main(string[] args) {
        Test t = new Test();
        t.Func1();
        t.Func2();
    }
}
Test.cs

これを


csc Test.cs

とコンパイルして実行してみてください。 何も表示されずに終了してしまうはずです。
では、今度は


csc /d:TEST Test.cs

とコンパイルして実行してみてください。 今度は"Func1"と表示されたと思います。
/d/defineの省略形なので"TEST"をdefineするとFunc1メソッドが実行されるわけです。 もちろん、ソースコード中に直接"#define TEST"と書いても同じようにコンパイルされます。
さて、コンパイルされた結果はどうなってるんでしょうか? ildasmで確認してみましょう(全部書くと長くなるので適当に省略しています)。


.method public void Func1()
{
    // 省略
}

.method public void Func2()
{
    // 省略
}

.method public static void  Main(string[] args)
{
  IL_0000:  newobj     instance void Test::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ret
}

何もdefineせずにコンパイルした場合


.method public void Func1()
{
    // 省略
}

.method public void Func2()
{
    // 省略
}

.method public static void  Main(string[] args)
{
  IL_0000:  newobj     instance void Test::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  callvirt   instance void Test::Func1()
  IL_000c:  ret
}
TESTをdefineしてコンパイルした場合

中身は省略してますが、どちらも、Func1メソッドとFunc2メソッドはちゃんとコンパイルされています。 しかし、「何もdefineせずにコンパイルした場合」のMainでは"new Test()"しただけでリターンしています。 「TESTをdefineしてコンパイルした場合」のMainは"new Test()"した後、Func1メソッドを呼び出しています。 どちらのMainにもFunc2メソッドの呼び出しは含まれていません。

こんな風にConditionalAttributeを使うと「文字列がdefineされていないとそのメソッドは無かったことになる」 んですが、メソッド自体はちゃんとコンパイルされて、そのかわりに「そのメソッドを呼び出してるコードが無かったことになる」んです。
もちろん、#ifでも同じことはでます。 けど、#ifだと「呼び出してるほうを#ifで括る」ことになりますが、ConditionalAttributeの場合は「呼ばれるほうにConditionalAttributeを付ける」ことになります。 呼び出してるほうは、あちこちに分散するのが普通ですが、呼ばれるほうは普通1つなので管理しやすいですし、理にもかなってると思います。

そうそう、属性をよく知らない人もいるかもしれませんが、こんな風にクラスやメソッドの直前に[xxxxx]なんて書くのを属性(英語だとAttributeね)といいます。 属性もクラスです(クラスリファレンスに載ってます)。 ただ、[xxxxx]と書くときに"Attribute"は省略していいことになってます(もちろん、書いてもいいです)。 なので、[ConditionalAttribute]と[Conditional]は同じ意味です。 クラス名自体は必ず(絶対じゃないんだけど)Attributeが付いてるので、そのつもりでリファレンスを見てください。 また、[Conditional("TEST")]と書くと、ConditionalAttributeクラスのコンストラクタに"TEST"を渡すという意味になります。


[トップ] [目次]

株式会社ディーバ 青柳 臣一
2002/04/13