はじめに
今回はConditionalAttribute
は呼び出し元のシンボル定義を参照していることについて取り上げたいと思います。
概要
そもそもConditional
属性とは?という方もいると思うので公式の説明を載せておきます。
指定した条件付きコンパイル シンボルが定義されていない場合、メソッド呼び出しまたは属性を無視するようコンパイラに指示します。
// 公式サンプル #define CONDITION1 #define CONDITION2 using System; using System.Diagnostics; class Test { static void Main() { Console.WriteLine("Calling Method1"); Method1(3); Console.WriteLine("Calling Method2"); Method2(); Console.WriteLine("Using the Debug class"); Debug.Listeners.Add(new ConsoleTraceListener()); Debug.WriteLine("DEBUG is defined"); } [Conditional("CONDITION1")] public static void Method1(int x) { Console.WriteLine("CONDITION1 is defined"); } [Conditional("CONDITION1"), Conditional("CONDITION2")] public static void Method2() { Console.WriteLine("CONDITION1 or CONDITION2 is defined"); } }
ConditionalAttribute クラス (System.Diagnostics) | Microsoft Learn
また昔私もConditional
属性について書いたので、よければそちらもどうぞ。
www.hanachiru-blog.com
気をつけたいこと
最初「Conditional
が定義されている側」にシンボル定義をすれば良いのかなと思っていたのですが、どうやら「呼び出し元側」にシンボル定義がされていないといけないみたいです。
// メソッドの呼び出し側にシンボル定義を行ったときにはメソッド呼び出しがスキップされない #define ENABLE_HOGE public static class Program { public static void Main(string[] args) { Program2.Hoge(); } }
public static class Program2 { [Conditional("ENABLE_HOGE")] public static void Hoge() { Console.WriteLine("Hoge"); } }
対処法
「Conditional
が定義されている側」のシンボル定義によって、メソッド呼び出しをスキップするかしないかを変更したい場合は以下のように書くことで実現できます。
#define ENABLE_HOGE public static class Program2 { // ENABLE_HOGEがシンボル定義されていたら、Hogeメソッド呼び出しがスキップされる #if !ENABLE_HOGE [Conditional("絶対に定義されないような文字列")] #endif public static void Hoge() { // Conditional属性を用いていてもHogeメソッドはコンパイルに含まれるので、コードサイズを減らしたいなら#ifで囲っておくのが吉 #if ENABLE_HOGE Console.WriteLine("Hoge"); #endif } }
またコメントにも書いておきましたが、Conditional
はあくまで呼び出し元のメソッド呼び出しがスキップされるかどうかのみ影響されます。ですので、メソッド自体はコンパイルに含まれます。
コードサイズを少しでも減らしたい場合は#if ~ #endif
で囲っておくのが吉でしょう。