1. ホーム
  2. c#

[解決済み] #if DEBUG vs. Conditional("DEBUG")

2022-03-22 11:08:19

質問

大規模なプロジェクトで、どちらを使うのが良いか、またその理由は?

#if DEBUG
    public void SetPrivateValue(int value)
    { ... }
#endif

または

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }

解決方法は?

それは、あなたが何を目指しているかによります。

  • #if DEBUG : ここにあるコードは、リリース時にILに届くこともないでしょう。
  • [Conditional("DEBUG")] : このコードはILに届きますが が呼び出されます。 は、呼び出し側がコンパイルされるときに DEBUG が設定されない限り、メソッドへのアクセスは省略されます。

個人的には、状況に応じて両方を使い分けています。

条件付き("DEBUG")の例です。 これは、リリース時にコードを編集する必要がないようにするためですが、デバッグ時には、タイプミスがないことを確認したいのです。この関数は、INotifyPropertyChangedの中でプロパティ名を使おうとしているときに、私が正しくタイプしているかどうかをチェックするものです。

[Conditional("DEBUG")]
[DebuggerStepThrough]
protected void VerifyPropertyName(String propertyName)
{
    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}",
            GetType(), propertyName));
}

を使用して関数を作成するのは、本当に避けたいものです。 #if DEBUG ただし、その関数のすべての呼び出しを同じ #if DEBUG :

#if DEBUG
    public void DoSomething() { }
#endif

    public void Foo()
    {
#if DEBUG
        DoSomething(); //This works, but looks FUGLY
#endif
    }

対になります。

[Conditional("DEBUG")]
public void DoSomething() { }

public void Foo()
{
    DoSomething(); //Code compiles and is cleaner, DoSomething always
                   //exists, however this is only called during DEBUG.
}


#if DEBUG の例です。 WCFの通信に異なるバインディングを設定しようとするときに使います。

#if DEBUG
        public const String ENDPOINT = "Localhost";
#else
        public const String ENDPOINT = "BasicHttpBinding";
#endif

最初の例では、コードはすべて存在しますが、DEBUGがオンになっていない限り無視されます。2番目の例では、DEBUGが設定されているかどうかに応じて、const ENDPOINTが"Localhost" または"BasicHttpBinding" に設定されています。


更新:重要かつ厄介な点を明確にするために、この回答を更新しています。もしあなたが ConditionalAttribute は、コンパイル時に呼び出しが省略されることを覚えておいてください。 実行時ではなく . ということです。

MyLibrary.dll

[Conditional("DEBUG")]
public void A()
{
    Console.WriteLine("A");
    B();
}

[Conditional("DEBUG")]
public void B()
{
    Console.WriteLine("B");
}

ライブラリがリリースモード(つまりDEBUGシンボルなし)に対してコンパイルされた場合、永遠に B() の中から A() への呼び出しが省略された場合でも A() が含まれるのは、呼び出し側のアセンブリでDEBUGが定義されているからです。