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)
{ ... }
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)
{ ... }
Antworten:
Es hängt wirklich davon ab, was Sie wollen:
#if DEBUG
: Der Code hier erreicht bei Veröffentlichung nicht einmal die IL.[Conditional("DEBUG")]
: Dieser Code erreicht die IL, Aufrufe der Methode werden jedoch weggelassen, es sei denn, DEBUG wird beim Kompilieren des Aufrufers festgelegt.Persönlich benutze ich beide je nach Situation:
Bedingt ("DEBUG") Beispiel: Ich verwende dies, damit ich später während der Veröffentlichung nicht zurückgehen und meinen Code bearbeiten muss, aber während des Debuggens möchte ich sicher sein, dass ich keine Tippfehler gemacht habe. Diese Funktion überprüft, ob ich einen Eigenschaftsnamen korrekt eingebe, wenn ich versuche, ihn in meinem INotifyPropertyChanged-Material 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 erstellen, es #if DEBUG
sei denn, Sie sind bereit, jeden Aufruf dieser Funktion mit demselben zu versehen #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 gesamte Code vorhanden, wird jedoch nur ignoriert, wenn DEBUG aktiviert ist. Im zweiten Beispiel wird der 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 sich für die Verwendung von entscheiden ConditionalAttribute
, beachten Sie, dass Aufrufe während der Kompilierung und nicht zur Laufzeit weggelassen werden . Das ist:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
Wenn die Bibliothek gegen den Freigabemodus kompiliert wird (dh kein DEBUG-Symbol), wird der Aufruf B()
von innen für immer A()
weggelassen, selbst wenn ein Aufruf von A()
enthalten ist, da DEBUG in der aufrufenden Assembly definiert ist.
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 ... während es im zweiten Fall existiert, aber bei allen Anrufern , die ohne das DEBUG-Symbol kompiliert wurden, werden diese Aufrufe weggelassen.
Wenn der Code und alle seine Anrufer in der gleichen Anordnung ist dieser Unterschied weniger wichtig - aber es bedeutet , dass im ersten Fall , dass Sie auch brauchen , um #if DEBUG
die um Aufruf als auch Code.
Persönlich würde ich den zweiten Ansatz empfehlen - aber Sie müssen den Unterschied zwischen ihnen in Ihrem Kopf klar halten.
Ich bin mir sicher, dass viele mit mir nicht einverstanden sein werden, aber nachdem ich als Build-Typ ständig gehört habe, dass "Aber es funktioniert auf meiner Maschine!", Habe ich den Standpunkt vertreten, dass Sie es so gut wie nie verwenden sollten. Wenn Sie wirklich etwas zum Testen und Debuggen benötigen, finden Sie heraus, wie Sie diese Testbarkeit vom tatsächlichen Produktionscode trennen können.
Abstrahieren Sie die Szenarien mit Verspottung in Komponententests, erstellen Sie einmalige Versionen von Dingen für einmalige Szenarien, die Sie testen möchten, aber fügen Sie keine Debug-Tests in den Code für Binärdateien ein, die Sie testen und für die Produktionsversion schreiben. Diese Debug-Tests verbergen nur mögliche Fehler vor Entwicklern, sodass sie erst später im Prozess gefunden werden.
#if debug
ein ähnliches Konstrukt in Ihrem Code?
#if DEBUG
damit andere nicht versehentlich Spam erhalten, während wir ein System testen, das E-Mails als Teil des Prozesses übertragen muss. Manchmal sind dies die richtigen Werkzeuge für den Job :)
Dieser kann auch nützlich sein:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
zur Laufzeit auch in Release-Builds aufgerufen werden muss.
Im ersten Beispiel ist SetPrivateValue
der Build nicht vorhanden, wenn er DEBUG
nicht definiert ist. Im zweiten Beispiel sind Aufrufe von SetPrivateValue
nicht im Build vorhanden, wenn er DEBUG
nicht definiert ist.
Im ersten Beispiel müssen Sie auch alle Anrufe SetPrivateValue
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, sodass eine Anwendung, die auf Ihre Bibliothek verweist, Ihre Funktion weiterhin verwenden kann (wenn die Bedingung erfüllt ist).
Wenn Sie die Anrufe weglassen 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
}
#if DEBUG
um Conditional("DEBUG")
nicht zu entfernen , die Anrufe zu dieser Funktion, es entfernt nur die Funktion von IL alltogether, so dass Sie immer noch Anrufe Funktion , die nicht (Kompilierungsfehler) nicht vorhanden ist .
Nehmen wir an, Ihr Code hatte auch eine #else
Anweisung, die eine Null-Stub-Funktion definierte und einen der Punkte von Jon Skeet ansprach. Es gibt einen zweiten wichtigen Unterschied zwischen den beiden.
Angenommen, die Funktion #if DEBUG
oder Conditional
ist in einer DLL vorhanden, auf die Ihre ausführbare Hauptprojektdatei verweist. Mit dem #if
wird die Auswertung der Bedingung im Hinblick auf die Kompilierungseinstellungen der Bibliothek durchgeführt. Mit dem Conditional
Attribut wird die Auswertung der Bedingung hinsichtlich der Kompilierungseinstellungen des Aufrufers durchgeführt.
Ich habe eine SOAP WebService-Erweiterung, um den Netzwerkverkehr mithilfe eines benutzerdefinierten Protokolls zu protokollieren [TraceExtension]
. Ich verwende dies nur für Debug- Builds und lasse Release- Builds aus. Verwenden Sie das #if DEBUG
, um das [TraceExtension]
Attribut zu verpacken und es so 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(...)
Normalerweise benötigen Sie es in Program.cs, wo Sie entscheiden möchten, ob Sie Debuggen mit Nicht-Debug-Code ausführen möchten, und dies auch meistens in Windows-Diensten. Also habe ich ein schreibgeschütztes Feld IsDebugMode erstellt und seinen 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
}