504 Stimmen

#if DEBUG vs. Conditional("DEBUG")

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

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

o

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

20 Stimmen

Siehe blogs.msdn.com/b/ericlippert/archive/2009/09/10/ für einige Gedanken zu dieser Frage.

2 Stimmen

Können Sie auch dies verwenden: if (Debugger.IsAttached) {...}

1 Stimmen

Hinweis für Unity-Entwickler: DEBUG bedeutet im Editor oder in Entwicklungs-Builds. forum.unity.com/threads/

655voto

myermian Punkte 30905

Es kommt wirklich darauf an, was Sie erreichen wollen:

  • #if DEBUG : Der hier enthaltene Code wird bei der Veröffentlichung nicht einmal die IL erreichen.
  • [Conditional("DEBUG")] : Dieser Code wird die IL erreichen, aber ruft auf. an die Methode wird ausgelassen, es sei denn, DEBUG ist beim Kompilieren des Aufrufers gesetzt.

Ich persönlich benutze beides, je nach Situation:

Conditional("DEBUG") Beispiel: Ich verwende dies, damit ich nicht zurückgehen und meinen Code später während der Veröffentlichung bearbeiten muss, aber während der Fehlersuche möchte ich sicher sein, dass ich keine Tippfehler gemacht habe. Diese Funktion prüft, ob ich einen Eigenschaftsnamen richtig eingebe, wenn ich versuche, ihn in meinem INotifyPropertyChanged-Zeug 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 sollten wirklich keine Funktion erstellen, die #if DEBUG es sei denn, Sie sind bereit, jeden Aufruf dieser Funktion mit demselben #if DEBUG :

#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 verwende 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 zwar vorhanden, wird aber nur dann ignoriert, wenn DEBUG eingeschaltet ist. Im zweiten Beispiel wird die Konstante ENDPOINT auf "Localhost" oder "BasicHttpBinding" gesetzt, je nachdem, ob DEBUG eingestellt ist oder nicht.


Aktualisierung: Ich aktualisiere diese Antwort, um einen wichtigen und heiklen Punkt zu klären. Wenn Sie sich für die Verwendung der ConditionalAttribute nicht vergessen, dass die Aufrufe während der Kompilierung ausgelassen werden, und nicht zur Laufzeit . Das heißt:

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 (d.h. ohne DEBUG-Symbol), wird sie immer den Aufruf von B() von innen A() ausgelassen, auch wenn ein Aufruf von A() ist enthalten, weil DEBUG in der aufrufenden Assembly definiert ist.

15 Stimmen

Die #if Debug für DoSomething muss nicht alle aufrufenden Anweisungen von #if DEBUG umgeben sein. Sie können entweder 1: nur #if DEBUG das Innere von DoSomething, oder, tun ein #else mit einer leeren Definition von DoSomething. Trotzdem hat mir Ihr Kommentar geholfen, den Unterschied zu verstehen, aber #if DEBUG muss nicht so hässlich sein, wie Sie gezeigt haben.

4 Stimmen

Wenn Sie nur #if DEBUG den Inhalt, die JIT kann immer noch einen Aufruf der Funktion, wenn Ihr Code läuft in einem Nicht-Debug-Build. Die Verwendung des Attributs Conditional bedeutet, dass das JIT weiß, dass es die Aufrufsite in einem Nicht-DEBUG-Build gar nicht ausgeben soll.

0 Stimmen

Die Bedingung schließt den Code nicht aus. Er markiert ihn mit Metadaten. Der DEBUG-Wert wird zur Kompilierzeit des CALLING-Codes abgeglichen. Dieser kann sich innerhalb oder außerhalb der Baugruppe befinden, die die markierte Methode enthält.

69voto

Jon Skeet Punkte 1325502

Nun, es ist erwähnenswert, dass sie keineswegs dasselbe bedeuten.

Wenn das DEBUG-Symbol nicht definiert ist, dann wird im ersten Fall das SetPrivateValue selbst nicht aufgerufen wird... während es im zweiten Fall zwar existiert, aber jede Anrufer die ohne das DEBUG-Symbol kompiliert werden, werden diese Aufrufe weggelassen.

Wenn der Code und alle seine Aufrufer in der gleichen Assembly sind, ist dieser Unterschied menos wichtig - aber es bedeutet, dass Sie im ersten Fall également haben müssen #if DEBUG um den aufrufen auch den Code.

Ich persönlich würde den zweiten Ansatz empfehlen - aber Sie müssen sich den Unterschied zwischen beiden klar vor Augen halten.

5 Stimmen

+1 für aufrufenden Code muss ebenfalls #if-Anweisungen enthalten. Das bedeutet, dass es eine Vermehrung von #if-Anweisungen geben wird...

0 Stimmen

Während die zweite Option (Bedingtes Attribut) in einigen Fällen schöner und sauberer ist, kann es erforderlich sein, die Tatsache mitzuteilen, dass ein Methodenaufruf während der Kompilierung aus der Assembly entfernt wird (z. B. durch eine Namenskonvention).

45voto

Jimmy Hoffa Punkte 5803

Ich bin mir sicher, dass viele anderer Meinung sind, aber da ich als Entwickler ständig höre: "Aber das funktioniert doch auf meinem Rechner!", vertrete ich den Standpunkt, dass man beides so gut wie nie verwenden sollte. Wenn Sie wirklich etwas zum Testen und Debuggen brauchen, finden Sie einen Weg, diese Testbarkeit vom eigentlichen Produktionscode zu trennen.

Abstrahieren Sie die Szenarien mit Mocking in Unit-Tests, erstellen Sie einmalige Versionen von Dingen für einmalige Szenarien, die Sie testen wollen, aber fügen Sie keine Debug-Tests in den Code für Binärdateien ein, die Sie testen und für die Produktionsfreigabe schreiben. Diese Debug-Tests verbergen mögliche Fehler nur vor den Entwicklern, so dass sie erst später im Prozess gefunden werden.

4 Stimmen

Ich stimme Ihnen völlig zu, Jimmy. Wenn Sie DI und Mocking für Ihre Tests verwenden, warum sollten Sie #if debug oder ein ähnliches Konstrukt in Ihrem Code?

6 Stimmen

Nicht nur zu Testzwecken, sondern auch in Debug-Builds setzen wir oft eine Standard-E-Mail an uns selbst, indem wir #if DEBUG damit wir beim Testen eines Systems, das als Teil des Prozesses E-Mails übertragen muss, nicht versehentlich andere spammen. Manchmal sind das die richtigen Werkzeuge für den Job :)

6 Stimmen

Ich würde im Allgemeinen mit Ihnen übereinstimmen, aber wenn Sie sich in einer Situation befinden, in der die Leistung von größter Bedeutung ist, dann möchten Sie den Code nicht mit überflüssigen Protokollierungs- und Benutzerausgaben überladen, aber ich stimme zu 100% zu, dass sie niemals verwendet werden sollten, um das grundlegende Verhalten zu ändern

18voto

sofsntp Punkte 1666

Auch dieser kann nützlich sein:

if (Debugger.IsAttached)
{
...
}

8 Stimmen

Ich persönlich sehe nicht, wie dies im Vergleich zu den anderen beiden Alternativen nützlich sein kann. Dies garantiert, dass der gesamte Block kompiliert wird, und Debugger.IsAttached muss auch in Release-Builds zur Laufzeit aufgerufen werden.

10voto

P Daddy Punkte 27687

Zum ersten Beispiel, SetPrivateValue nicht im Build vorhanden sein, wenn DEBUG nicht definiert ist, mit dem zweiten Beispiel, ruft auf. a SetPrivateValue im Build nicht vorhanden ist, wenn DEBUG ist nicht definiert.

Im ersten Beispiel müssen Sie alle Aufrufe an SetPrivateValue con #if DEBUG auch.

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

Wenn Sie die Aufrufe weglassen und den Platz des Aufrufenden sparen wollen, können Sie eine Kombination der beiden Techniken verwenden:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X