Conditional属性

部屋を整理してたら、昔勉強したC#の本が出てきて、こんなのあったなぁと思い出したので遊んでみた。
#ifdef HOGE 〜 #endif みたいなのをまたちょっと違う方法で実現できる属性。条件付きメソッド。TraceやDebugあたりの仕組みを実現するために作ったんだろうけど、誰でも使えたり。

#define A
#define B

using System;
using System.Diagnostics;

namespace ConditionalTest
{
  class Program
  {
    static void Main( string[] args )
    {
      if ( args.Length == 1 )
        ConA();

      ConB();

      Console.Read();
    }

    [Conditional( "A" )]
    private static void ConA()
    {
      Console.WriteLine( "A" );
    }

    [Conditional( "B" )]
    private static void ConB()
    {
      Console.WriteLine( "B" );
    }
  }
}

先頭のdefineを消すだけで、ConAやConBのコールがIL上では呼ぶところごと消えてなくなります!ソース上は呼んでるように見えるので、たまたまコードを見たチームメイトが悲鳴をあげたりとかあるかもw
ソース上のコールは残って、ILだけで消えるってのは精神衛生上よろしくないかもしれません。手間いらずな反面、まぎらわしい〜。
このサンプルのようにifの中だったりするとどうよ?っていじめてみたけど、正しく生成されました。やるねぇ。でも、こういう使い方はするべきじゃないです、はい。

#define A, #define B のときのデバッグコンパイル結果のIL

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // コード サイズ       33 (0x21)
  .maxstack  2
  .locals init ([0] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldlen
  IL_0003:  conv.i4
  IL_0004:  ldc.i4.1
  IL_0005:  ceq
  IL_0007:  ldc.i4.0
  IL_0008:  ceq
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  brtrue.s   IL_0014
  IL_000e:  call       void ConditionalTest.Program::ConA()
  IL_0013:  nop
  IL_0014:  call       void ConditionalTest.Program::ConB()
  IL_0019:  nop
  IL_001a:  call       int32 [mscorlib]System.Console::Read()
  IL_001f:  pop
  IL_0020:  ret
} // end of method Program::Main

#define B だけのときのデバッグコンパイル結果のIL

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // コード サイズ       27 (0x1b)
  .maxstack  2
  .locals init ([0] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldlen
  IL_0003:  conv.i4
  IL_0004:  ldc.i4.1
  IL_0005:  ceq
  IL_0007:  ldc.i4.0
  IL_0008:  ceq
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  brtrue.s   IL_000e
  IL_000e:  call       void ConditionalTest.Program::ConB()
  IL_0013:  nop
  IL_0014:  call       int32 [mscorlib]System.Console::Read()
  IL_0019:  pop
  IL_001a:  ret
} // end of method Program::Main

call ConA() が消えてる。

#ちょっとコード変更しました。最初のは正しくいじめてなかった。