Sarò impopolare e dirò di sì, è una cattiva pratica. SE la funzionalità del codice si basa su di esso per implementare la logica condizionale.
vale a dire
if(quickLogicA && slowLogicB) {doSomething();}
è buono, ma
if(logicA && doSomething()) {andAlsoDoSomethingElse();}
è male, e sicuramente nessuno sarebbe d'accordo ?!
if(doSomething() || somethingElseIfItFailed() && anotherThingIfEitherWorked() & andAlwaysThisThing())
{/* do nothing */}
Ragionamento:
Il tuo errore di codice se vengono valutati entrambi i lati anziché semplicemente non eseguire la logica. È stato sostenuto che questo non è un problema, l'operatore 'and' è definito in c # quindi il significato è chiaro. Tuttavia, sostengo che questo non è vero.
Motivo 1. Storico
Fondamentalmente stai facendo affidamento su (ciò che originariamente era inteso come) un'ottimizzazione del compilatore per fornire funzionalità nel tuo codice.
Sebbene in c # le specifiche del linguaggio garantiscano il booleano 'e' l'operatore fa corto circuito. Questo non è vero per tutte le lingue e compilatori.
wikipeda elenca varie lingue e la loro opinione sul corto circuito http://en.wikipedia.org/wiki/Short-circuit_evaluation, come puoi, ci sono molti approcci. E un paio di problemi extra in cui non vado qui.
In particolare, FORTRAN, Pascal e Delphi hanno flag di compilazione che attivano questo comportamento.
Pertanto: è possibile che il codice funzioni quando viene compilato per il rilascio, ma non per il debug o con un compilatore alternativo ecc.
Motivo 2. Differenze linguistiche
Come puoi vedere da Wikipedia, non tutte le lingue adottano lo stesso approccio al corto circuito, anche quando specificano come gli operatori booleani dovrebbero gestirlo.
In particolare l'operatore 'e' di VB.Net non mette in corto circuito e TSQL ha alcune peculiarità.
Dato che è probabile che una moderna "soluzione" includa un numero di lingue, come javascript, regex, xpath ecc., È necessario tenerne conto quando si chiarisce la funzionalità del codice.
Motivo 3. Differenze all'interno di una lingua
Ad esempio VB inline if si comporta diversamente dal suo if. Ancora una volta nelle applicazioni moderne il tuo codice può spostarsi tra, ad esempio code behind e un modulo web incorporato, devi essere consapevole delle differenze di significato.
Motivo 4. L'esempio specifico di null che controlla il parametro di una funzione
Questo è un molto buon esempio. In questo è qualcosa che fanno tutti, ma in realtà è una cattiva pratica quando ci pensi.
È molto comune vedere questo tipo di controllo in quanto riduce notevolmente le righe di codice. Dubito che qualcuno lo tirerebbe fuori in una recensione di codice. (e ovviamente dai commenti e dalla valutazione puoi vedere che è popolare!)
Tuttavia, non riesce le migliori pratiche per più di un motivo!
È molto chiaro da numerose fonti, che la migliore pratica è controllare la validità dei parametri prima di utilizzarli e generare un'eccezione se non sono validi. Lo snippet di codice non mostra il codice circostante, ma probabilmente dovresti fare qualcosa del tipo:
if (smartphone == null)
{
//throw an exception
}
// perform functionality
Stai chiamando una funzione dall'interno dell'istruzione condizionale. Anche se il nome della tua funzione implica che calcola semplicemente un valore, può nascondere effetti collaterali. per esempio
Smartphone.GetSignal() { this.signal++; return this.signal; }
else if (smartphone.GetSignal() < 1)
{
// Do stuff
}
else if (smartphone.GetSignal() < 2)
{
// Do stuff
}
le migliori pratiche suggeriscono:
var s = smartphone.GetSignal();
if(s < 50)
{
//do something
}
Se applichi queste migliori pratiche al tuo codice, puoi vedere che la tua opportunità di ottenere un codice più breve attraverso l'uso del condizionale nascosto scompare. La migliore pratica è fare qualcosa , gestire il caso in cui lo smartphone è nullo.
Penso che scoprirai che questo vale anche per altri usi comuni. Devi ricordare che abbiamo anche:
condizionali in linea
var s = smartphone!=null ? smartphone.GetSignal() : 0;
e null coalescenza
var s = smartphoneConnectionStatus ?? "No Connection";
che forniscono funzionalità simili di lunghezza del codice funzione con maggiore chiarezza
numerosi link per supportare tutti i miei punti:
https://stackoverflow.com/questions/1158614/what-is-the-best-practice-in-case-one-argument-is-null
Convalida dei parametri del costruttore in C # - Best practice
Si dovrebbe verificare la null se non si aspetta null?
https://msdn.microsoft.com/en-us/library/seyhszts%28v=vs.110%29.aspx
https://stackoverflow.com/questions/1445867/why-would-a-language-not-use-short-circuit-evaluation
http://orcharddojo.net/orchard-resources/Library/DevelopmentGuidelines/BestPractices/CSharp
esempi di flag del compilatore che influiscono sul corto circuito:
Fortran: "sce | nosce Per impostazione predefinita, il compilatore esegue la valutazione del corto circuito in espressioni logiche selezionate utilizzando le regole XL Fortran. La specifica di sce consente al compilatore di utilizzare regole non XL Fortran. Il compilatore eseguirà la valutazione del corto circuito se le regole correnti lo consentono Il valore predefinito è nosce. "
Pascal: "B - Una direttiva flag che controlla la valutazione del corto circuito. Vedere Ordine di valutazione degli operandi di operatori diadici per ulteriori informazioni sulla valutazione del corto circuito. Vedere anche l'opzione del compilatore -sc per il compilatore della riga di comando per ulteriori informazioni ( documentato nel Manuale dell'utente). "
Delphi: "Delphi supporta la valutazione del corto circuito per impostazione predefinita. Può essere disattivato usando la direttiva del compilatore {$ BOOLEVAL OFF}."