大規模プロジェクトではどちらを使用するのが良いのでしょうか。
#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シンボルなし)でコンパイルされている場合、呼び出し元のアセンブリでDEBUGが定義されているため、B()
の呼び出しが含まれていても、A()
内からのA()
の呼び出しは永久に省略されます。
まあ、それはまったく同じことを意味しないことに注意する価値があります。
DEBUGシンボルが定義されていない場合、最初の場合はSetPrivateValue
自体は呼び出されませんが、2番目の場合は存在しますが、callers who DEBUGシンボルなしでコンパイルすると、これらの呼び出しは省略されます。
コードとそのすべての呼び出し元が同じアセンブリ内にある場合、この違いはless重要です-ただし、最初のケースではalsoが必要です#if DEBUG
呼び出しコードの周りにも。
個人的には、2番目のアプローチをお勧めしますが、頭の中でそれらの違いを明確に保つ必要があります。
私は賛成できないと確信していますが、ビルド担当者として「でもそれは私のマシンでは動作します」と聞いて時間を費やしてきたので、私はあなたがどちらも使うべきではないという立場を取ります。あなたが本当にテストとデバッグのために何かを必要とするならば、そのテスト容易性を実際の生産コードから切り離す方法を考え出してください。
単体テストでモックすることでシナリオを抽象化し、テストしたい1つのシナリオに対して1つのバージョンのものを作成します。ただし、実稼働リリース用にテストして作成するバイナリのコードにデバッグ用のテストを入れないでください。これらのデバッグテストは、潜在的なバグを開発者から隠すだけなので、プロセスの後半で発見されることはありません。
これも便利です。
if (Debugger.IsAttached)
{
...
}
最初の例では、SetPrivateValue
が定義されていない場合、DEBUG
はビルドに存在しません。2番目の例では、SetPrivateValue
が定義されていない場合、 呼び出し はDEBUG
に対して存在しません。
最初の例では、SetPrivateValue
への呼び出しを#if DEBUG
でラップする必要があります。
2番目の例では、SetPrivateValue
の呼び出しは省略されますが、SetPrivateValue
自体はまだコンパイルされることに注意してください。これは、ライブラリを構築している場合に便利です。したがって、ライブラリを参照しているアプリケーションは、(条件が満たされていれば)それでも関数を使用できます。
呼び出しを省略して呼び出し先のスペースを節約したい場合は、2つの方法を組み合わせて使用できます。
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
Jon Skeetの要点の1つに対処するために、コードにnullスタブ関数を定義する#else
ステートメントも含まれているとしましょう。 2つの間に2番目の重要な違いがあります。
メインプロジェクトの実行可能ファイルによって参照されるDLLに#if DEBUG
またはConditional
関数が存在するとします。 #if
を使用して、条件付きの評価はライブラリのコンパイル設定に関して実行されます。 Conditional
属性を使用して、呼び出し元のコンパイル設定に関して条件付きの評価が実行されます。
カスタム[TraceExtension]を使用してネットワークトラフィックを記録するためのSOAP WebService拡張があります。これはデバッグビルドにのみ使用し、リリースビルドからは省略します。 #if DEBUGを使用して[TraceExtension]属性をラップし、それをリリースビルドから削除します。
#if DEBUG
[TraceExtension]
#endif
[System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )]
[ more attributes ...]
public DatabaseResponse[] GetDatabaseResponse( ...)
{
object[] results = this.Invoke("GetDatabaseResponse",new object[] {
... parmeters}};
}
#if DEBUG
[TraceExtension]
#endif
public System.IAsyncResult BeginGetDatabaseResponse(...)
#if DEBUG
[TraceExtension]
#endif
public DatabaseResponse[] EndGetDatabaseResponse(...)
通常、Program.csで必要になるでしょう。そこでは、Debug以外のコードでDebugを実行し、それをWindows Servicesで実行することを決定します。そこで、読み取り専用のフィールドIsDebugModeを作成し、その値を次のように静的コンストラクタに設定しました。
static class Program
{
#region Private variable
static readonly bool IsDebugMode = false;
#endregion Private variable
#region Constrcutors
static Program()
{
#if DEBUG
IsDebugMode = true;
#endif
}
#endregion
#region Main
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (IsDebugMode)
{
MyService myService = new MyService(args);
myService.OnDebug();
}
else
{
ServiceBase[] services = new ServiceBase[] { new MyService (args) };
services.Run(args);
}
}
#endregion Main
}