17.4.2 Conditional 属性 (C#)

ビューの切り替え:
スクリプトなし
C# 言語の仕様
17.4.2 Conditional 属性

Conditional 属性を使用すると、条件付きメソッドの定義が可能になります。Conditional 属性は、条件付きコンパイル シンボルをテストすることによって条件を示します。条件付きメソッドの呼び出しは、呼び出しが行われた時点でこのシンボルが定義されているかどうかによって、実際に含まれるか省略されるかが決まります。シンボルが定義されている場合は呼び出しが行われ、定義されていない場合は呼び出し (呼び出しのパラメータの評価も含む) が行われません。

namespace System.Diagnostics
{
   [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
   public class ConditionalAttribute: Attribute
   {
      public ConditionalAttribute(string conditionString) {...}
      public string ConditionString { get {...} }
   }
}

条件付きメソッドには、次の制限事項があります。

  • 条件付きメソッドは、クラス宣言または構造体宣言のメソッドである必要があります。インターフェイス宣言のメソッドで Conditional 属性が指定されていると、コンパイル エラーになります。
  • 条件付きメソッドは、void 型の戻り値を持つ必要があります。
  • 条件付きメソッドには、override 修飾子を設定できません。ただし、条件付きメソッドに virtual 修飾子を設定することはできます。この修飾子を持つメソッドのオーバーライドは暗黙的に条件付きであり、明示的に Conditional 属性を設定することはできません。
  • 条件付きメソッドには、インターフェイス メソッドの実装は使用できません。それ以外の場合は、コンパイル エラーが発生します。

また、条件付きメソッドを delegate-creation-expression で使用すると、コンパイル エラーが発生します。次に例を示します。

#define DEBUG
using System;
using System.Diagnostics;
class Class1 
{
   [Conditional("DEBUG")]
   public static void M() {
      Console.WriteLine("Executed Class1.M");
   }
}
class Class2
{
   public static void Test() {
      Class1.M();
   }
}

この例では、Class1.M を条件付きメソッドとして宣言します。Class2Test メソッドがこのメソッドを呼び出します。条件付きコンパイル シンボル DEBUG が定義されているため、Class2.Test が呼び出されると、M が呼び出されます。シンボル DEBUG が定義されていなかった場合、Class2.TestClass1.M を呼び出しません。

条件付きメソッドの呼び出しが含まれるか除外されるかは、呼び出しの時点での条件付きコンパイル シンボルによって制御されます。次に例を示します。

class1.cs ファイル :

using System.Diagnostics;
class Class1 
{
   [Conditional("DEBUG")]
   public static void F() {
      Console.WriteLine("Executed Class1.F");
   }
}

class2.cs ファイル :

#define DEBUG
class Class2
{
   public static void G() {
      Class1.F();            // F is called
   }
}

class3.cs ファイル :

#undef DEBUG
class Class3
{
   public static void H() {
      Class1.F();            // F is not called
   }
}

この例のクラス Class2Class3 には、それぞれ条件付きメソッド Class1.F の呼び出しが設定されています。このメソッドの呼び出しは、DEBUG が定義されているかどうかによって決まります。このシンボルは、Class2 では定義されていますが Class3 では定義されていません。このため、Class2 での F の呼び出しは行われますが、Class3 での F の呼び出しは行われません。

継承チェイン内で条件付きメソッドを使用すると、混乱する可能性があります。base.M の形式の条件付きメソッドを base を使用して呼び出す場合は、通常の条件付きメソッドの呼び出し規約に従います。次に例を示します。

class1.cs ファイル :

using System;
using System.Diagnostics;
class Class1 
{
   [Conditional("DEBUG")]
   public virtual void M() {
      Console.WriteLine("Class1.M executed");
   }
}

class2.cs ファイル :

using System;
class Class2: Class1
{
   public override void M() {
      Console.WriteLine("Class2.M executed");
      base.M();                  // base.M is not called!
   }
}

class3.cs ファイル :

#define DEBUG
using System;
class Class3
{
   public static void Test() {
      Class2 c = new Class2();
      c.M();                     // M is called
   }
}

Class2 には、基本クラスで定義されている M の呼び出しがあります。基本メソッドはシンボル DEBUG の存在に基づく条件付きメソッドですが、このシンボルは未定義であるため、この呼び出しは省略されます。このため、メソッドはコンソールに "Class2.M executed" と書き込むだけです。pp-declaration を上手に使うと、この問題を解決できます。