Quale è meglio usare e perché su un grande progetto:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
o
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Quale è meglio usare e perché su un grande progetto:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
o
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Risposte:
Dipende davvero da cosa stai cercando:
#if DEBUG
: Il codice qui non raggiungerà nemmeno l'IL al rilascio.[Conditional("DEBUG")]
: Questo codice raggiungerà IL, tuttavia le chiamate al metodo verranno omesse a meno che DEBUG non sia impostato durante la compilazione del chiamante.Personalmente uso entrambi a seconda della situazione:
Esempio condizionale ("DEBUG"): lo uso in modo da non dover tornare indietro e modificare il mio codice in seguito durante il rilascio, ma durante il debug voglio essere sicuro di non aver fatto errori di battitura. Questa funzione verifica che io digiti correttamente il nome di una proprietà quando provo ad usarlo nelle mie cose 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));
}
Non vuoi davvero creare una funzione usando a #if DEBUG
meno che tu non sia disposto a concludere ogni chiamata a quella funzione con la stessa #if DEBUG
:
#if DEBUG
public void DoSomething() { }
#endif
public void Foo()
{
#if DEBUG
DoSomething(); //This works, but looks FUGLY
#endif
}
contro:
[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 esempio DEBUG: lo uso quando cerco di impostare diversi binding per la comunicazione WCF.
#if DEBUG
public const String ENDPOINT = "Localhost";
#else
public const String ENDPOINT = "BasicHttpBinding";
#endif
Nel primo esempio, il codice esiste tutto, ma viene semplicemente ignorato a meno che DEBUG non sia attivo. Nel secondo esempio, const ENDPOINT è impostato su "Localhost" o "BasicHttpBinding" a seconda che DEBUG sia impostato o meno.
Aggiornamento: sto aggiornando questa risposta per chiarire un punto importante e difficile. Se si sceglie di utilizzare il ConditionalAttribute
, tenere presente che le chiamate vengono omesse durante la compilazione e non in fase di esecuzione . Questo è:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
Quando la libreria viene compilata in modalità di rilascio (ovvero nessun simbolo DEBUG), per sempre la chiamata B()
dall'interno verrà A()
omessa, anche se A()
viene inclusa una chiamata a perché DEBUG è definito nell'assembly chiamante.
Bene, vale la pena notare che non significano affatto la stessa cosa.
Se il simbolo DEBUG non è definito, nel primo caso lo SetPrivateValue
stesso non verrà chiamato ... mentre nel secondo caso esisterà, ma tutti i chiamanti che sono compilati senza il simbolo DEBUG avranno quelle chiamate omesse.
Se il codice e tutti i suoi interlocutori sono nello stesso gruppo di questa differenza è meno importante - ma significa che nel primo caso è anche bisogno di avere #if DEBUG
intorno al chiamante codice pure.
Personalmente consiglierei il secondo approccio, ma devi tenere chiara la differenza tra loro nella tua testa.
Sono sicuro che molti non saranno d'accordo con me, ma dopo aver trascorso del tempo come un ragazzo di costruzione ascoltando costantemente "Ma funziona sulla mia macchina!", Prendo il punto di vista che non dovresti praticamente mai usare neanche. Se hai davvero bisogno di qualcosa per il test e il debug, cerca un modo per rendere tale testabilità separata dal codice di produzione effettivo.
Estrarre gli scenari con derisione nei test unitari, creare versioni una tantum delle cose per scenari una tantum che si desidera testare, ma non inserire i test per il debug nel codice per i binari che si testano e scrivono per la versione di produzione. Questi test di debug nascondono solo possibili bug dagli sviluppatori, in modo che non vengano trovati più avanti nel processo.
#if debug
o un costrutto simile nel tuo codice?
#if DEBUG
modo da non spammare accidentalmente altri durante il test di un sistema che deve trasmettere e-mail come parte del processo. A volte questi sono gli strumenti giusti per il lavoro :)
Anche questo può essere utile:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
debba essere chiamato in fase di esecuzione anche nelle build di rilascio.
Con il primo esempio, SetPrivateValue
non esisterà nella build se DEBUG
non è definito, con il secondo esempio, le chiamate a SetPrivateValue
non esisteranno nella build se DEBUG
non è definito.
Con il primo esempio, si dovrà avvolgere qualsiasi chiamata a SetPrivateValue
con #if DEBUG
pure.
Con il secondo esempio, le chiamate a SetPrivateValue
verranno omesse, ma attenzione che SetPrivateValue
verrà comunque compilato. Questo è utile se stai costruendo una libreria, quindi un'applicazione che fa riferimento alla tua libreria può ancora usare la tua funzione (se la condizione è soddisfatta).
Se si desidera omettere le chiamate e salvare lo spazio del chiamante, è possibile utilizzare una combinazione delle due tecniche:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
in giro Conditional("DEBUG")
non rimuove le chiamate a tale funzione, rimuove solo la funzione da IL alltogether, così hai ancora chiamate a funzione che non esiste (errori di compilazione).
Supponiamo che il tuo codice abbia anche #else
un'istruzione che definisce una funzione di stub null, indirizzando uno dei punti di Jon Skeet. C'è una seconda importante distinzione tra i due.
Supponiamo che la funzione #if DEBUG
o Conditional
esista in una DLL a cui fa riferimento l'eseguibile del progetto principale. Usando il #if
, la valutazione del condizionale verrà eseguita riguardo alle impostazioni di compilazione della libreria. Utilizzando l' Conditional
attributo, la valutazione del condizionale verrà eseguita in relazione alle impostazioni di compilazione dell'invocatore.
Ho un'estensione SOAP WebService per registrare il traffico di rete utilizzando un'abitudine [TraceExtension]
. Lo uso solo per build di debug e ometto dalle build di rilascio . Utilizzare il #if DEBUG
per avvolgere l' [TraceExtension]
attributo rimuovendolo così dalle build di rilascio .
#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(...)
Di solito ne avresti bisogno in Program.cs dove vuoi decidere di eseguire il debug su codice non di debug e quello troppo principalmente nei servizi di Windows. Quindi ho creato un campo di sola lettura IsDebugMode e impostato il suo valore nel costruttore statico come mostrato di seguito.
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
}