it-swarm.com.de

#if DEBUG vs. Conditional ("DEBUG")

Was ist besser zu verwenden und warum bei einem großen Projekt:

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

oder

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

Es hängt wirklich davon ab, was Sie anstreben:

  • #if DEBUG: Der Code hier erreicht nicht einmal die IL bei Veröffentlichung.
  • [Conditional("DEBUG")]: Dieser Code erreicht die AWL. Aufrufe der Methode werden jedoch weggelassen, es sei denn, DEBUG wird beim Kompilieren des Aufrufers gesetzt.

Persönlich benutze ich je nach Situation beides:

Bedingtes ("DEBUG") Beispiel: Ich benutze dies, damit ich meinen Code später während der Veröffentlichung nicht mehr bearbeiten muss, aber während des Debuggens möchte ich sichergehen, dass ich keine Tippfehler gemacht habe. Diese Funktion überprüft, ob ich einen Eigenschaftsnamen richtig eingebe, wenn ich versuche, ihn in meinem INotifyPropertyChanged-Zeugs zu verwenden.

[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));
}

Sie möchten wirklich keine Funktion mit #if DEBUG erstellen, es sei denn, Sie möchten jeden Aufruf dieser Funktion mit demselben #if DEBUG abschließen:

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

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

gegen:

[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-Beispiel: Ich benutze dies, wenn ich versuche, verschiedene Bindungen für die WCF-Kommunikation einzurichten.

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

Im ersten Beispiel ist der Code vollständig vorhanden, wird jedoch ignoriert, es sei denn, DEBUG ist aktiviert. Im zweiten Beispiel wird die const ENDPOINT auf "Localhost" oder "BasicHttpBinding" gesetzt, je nachdem, ob DEBUG gesetzt ist oder nicht.


Update: Ich aktualisiere diese Antwort, um einen wichtigen und kniffligen Punkt zu klären. Wenn Sie ConditionalAttribute verwenden, beachten Sie, dass Aufrufe während der Kompilierung weggelassen werden und nicht zur Laufzeit. Das ist:

MyLibrary.dll

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

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

Wenn die Bibliothek im Freigabemodus kompiliert wird (dh ohne DEBUG-Symbol), wird der Aufruf von B() innerhalb von A() für immer weggelassen, auch wenn ein Aufruf von A() aufgrund von DEBUG enthalten ist wird in der aufrufenden Assembly definiert.

549
m-y

Nun, es ist erwähnenswert, dass sie überhaupt nicht dasselbe bedeuten.

Wenn das DEBUG-Symbol nicht definiert ist, wird im ersten Fall das SetPrivateValue selbst nicht aufgerufen ... im zweiten Fall wird es existieren, aber alle Aufrufer wer sind Ohne das DEBUG-Symbol kompiliert, werden diese Aufrufe ausgelassen.

Wenn sich der Code und alle seine Aufrufer in derselben Assembly befinden, ist dieser Unterschied weniger wichtig - aber dies bedeutet, dass Sie im ersten Fall auch#if DEBUG benötigen. auch um den aufrufenden Code.

Persönlich würde ich den zweiten Ansatz empfehlen - aber Sie müssen den Unterschied zwischen ihnen klar im Kopf behalten.

61
Jon Skeet

Ich bin mir sicher, dass viele mit mir nicht einverstanden sind, aber nachdem ich als Builder ständig gehört habe, "Aber es funktioniert auf meiner Maschine!", Gehe ich davon aus, dass Sie so gut wie nie etwas verwenden sollten. Wenn Sie wirklich etwas zum Testen und Debuggen benötigen, finden Sie eine Möglichkeit, diese Testbarkeit vom tatsächlichen Produktionscode zu trennen.

Zusammenfassung der Szenarien durch Verspotten in Komponententests, Erstellen von einmaligen Versionen von Dingen für einmalige Szenarien, die Sie testen möchten, aber fügen Sie keine Tests zum Debuggen in den Code für Binärdateien ein, die Sie testen und für die Produktionsfreigabe schreiben. Diese Debug-Tests verbergen nur mögliche Fehler vor Entwicklern, sodass sie erst später im Prozess gefunden werden.

42
Jimmy Hoffa

Dieser kann auch nützlich sein:

if (Debugger.IsAttached)
{
...
}
12
sofsntp

Im ersten Beispiel ist SetPrivateValue im Build nicht vorhanden, wenn DEBUG nicht definiert ist. Im zweiten Beispiel ist Aufrufe an SetPrivateValue nicht vorhanden im Build, wenn DEBUG nicht definiert ist.

Im ersten Beispiel müssen Sie alle Aufrufe von SetPrivateValue auch mit #if DEBUG abschließen.

Im zweiten Beispiel werden die Aufrufe von SetPrivateValue weggelassen, aber beachten Sie, dass SetPrivateValue selbst noch kompiliert wird. Dies ist nützlich, wenn Sie eine Bibliothek erstellen, damit eine Anwendung, die auf Ihre Bibliothek verweist, Ihre Funktion weiterhin verwenden kann (sofern die Bedingung erfüllt ist).

Wenn Sie die Anrufe auslassen und den Platz des Angerufenen sparen möchten, können Sie eine Kombination der beiden Techniken verwenden:

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
    #if DEBUG
    // method body here
    #endif
}
9
P Daddy

Nehmen wir an, Ihr Code hatte auch eine #else -Anweisung, die eine Null-Stub-Funktion definierte und einen von Jon Skeets Punkten ansprach. Es gibt einen zweiten wichtigen Unterschied zwischen den beiden.

Angenommen, die Funktion #if DEBUG oder Conditional ist in einer DLL vorhanden, auf die die ausführbare Datei Ihres Hauptprojekts verweist. Mit dem #if wird die Bewertung der Bedingung im Hinblick auf die Kompilierungseinstellungen der Bibliothek durchgeführt. Mit dem Attribut Conditional wird die Bewertung der Bedingung in Bezug auf die Kompilierungseinstellungen des Aufrufers durchgeführt.

4
Kennet Belenky

Ich habe eine SOAP WebService-Erweiterung, um den Netzwerkverkehr mithilfe einer benutzerdefinierten [TraceExtension] zu protokollieren. Ich verwende dies nur für Debug-Builds und lasse Release-Builds aus. Verwenden Sie #if DEBUG, um das Attribut [TraceExtension] zu umbrechen und es somit aus Release-Builds zu entfernen.

#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(...)
2

Normalerweise benötigen Sie es in Program.cs, wo Sie sich entscheiden möchten, entweder Debug für Nicht-Debug-Code auszuführen, und das meistens auch in Windows-Diensten. Deshalb habe ich ein schreibgeschütztes Feld IsDebugMode erstellt und dessen Wert im statischen Konstruktor wie unten gezeigt festgelegt.

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        
}
0
Yashwant Shukla