Quando è appropriato usare una dichiarazione switch classica (fall-through)? Tale uso è raccomandato e incoraggiato o dovrebbe essere evitato a tutti i costi?
Ecco un esempio in cui sarebbe utile.
public Collection<LogItems> GetAllLogItems(Level level) {
Collection<LogItems> result = new Collection<LogItems>();
switch (level) {
// Note: fall through here is INTENTIONAL
case All:
case Info:
result.Add(GetItemsForLevel(Info));
case Warning:
result.Add(GetItemsForLevel(Warning));
case Error:
result.Add(GetItemsForLevel(Error));
case Critical:
result.Add(GetItemsForLevel(Critical));
case None:
}
return result;
}
Questo genere di cose (dove un caso include l'altro) è piuttosto raro, credo, ed è per questo che alcune lingue più recenti non permettono il fallover o richiedono una sintassi speciale per esso.
Li uso quando determinate funzionalità devono essere applicate per più di un valore. Ad esempio, supponi di avere un oggetto con una proprietà chiamata operationCode. Se il codice è uguale a 1, 2, 3 o 4, si desidera avviareOperazioneX (). Se è 5 o 6, si desidera avviareOperazioneY () e 7 si avviaOperazioneZ (). Perché 7 casi completi con funzionalità e interruzioni quando è possibile utilizzare i fall-through?
Penso che sia completamente valido in determinate situazioni, specialmente se evita 100 dichiarazioni if if. =)
Li ho usati occasionalmente, penso sia sempre un utilizzo appropriato, ma solo se inclusi nel commento appropriato.
I casi fall-through sono perfettamente a posto. Trovo spesso che un'enumerazione viene utilizzata in molti luoghi e che quando non è necessario differenziare alcuni casi è più semplice utilizzare la logica fall-through.
Ad esempio (notare i commenti esplicativi):
public boolean isAvailable(Server server, HealthStatus health) {
switch(health) {
// Equivalent positive cases
case HEALTHY:
case UNDER_LOAD:
return true;
// Equivalent negative cases
case FAULT_REPORTED:
case UNKNOWN:
case CANNOT_COMMUNICATE:
return false;
// Unknown enumeration!
default:
LOG.warn("Unknown enumeration " + health);
return false;
}
}
Trovo che questo tipo di utilizzo sia perfettamente accettabile.
Dipende da:
I due problemi principali associati alla caduta di un caso in un altro sono:
Rende il tuo codice dipendente dall'ordine delle istruzioni del caso. Non è questo il caso se non cadi mai, e aggiunge un grado di complessità che spesso non è gradito.
Non è ovvio che il codice per un caso includa il codice per uno o più casi successivi.
Alcuni luoghi proibiscono esplicitamente di cadere. Se non lavori in un posto del genere, e se sei a tuo agio con la pratica, e se rompere il codice in questione non causerà alcuna vera sofferenza, allora potrebbe non essere la cosa peggiore del mondo. Se lo fai, però, assicurati di inserire un commento che attiri l'attenzione nelle vicinanze per avvertire quelli che verranno dopo (incluso il futuro).
Ecco un breve esempio di fall-through che semplifica la vita:
function get_julian_day (date) {
int utc_date = date.getUTCDate();
int utc_month = date.getUTCMonth();
int julian_day = 0;
switch (utc_month) {
case 11: julian_day += 30;
case 10: julian_day += 31;
case 9: julian_day += 30;
case 8: julian_day += 31;
case 7: julian_day += 31;
case 6: julian_day += 30;
case 5: julian_day += 31;
case 4: julian_day += 30;
case 3: julian_day += 31;
case 2: julian_day += 28;
case 1: julian_day += 31;
default: break;
}
return julian_day + utc_date;
}
Se sento il bisogno di passare da un caso all'altro (raro, devo ammetterlo), preferisco essere molto esplicito e goto case
, naturalmente, che presume che la tua lingua lo supporti.
Poiché la caduta è così rara e molto facile da trascurare durante la lettura del codice, ritengo che sia appropriato essere esplicito - e un goto, anche se si tratta di un caso, dovrebbe risaltare come un pollice dolente.
Aiuta anche a evitare i bug che possono verificarsi quando le istruzioni del caso vengono riordinate.
Leggi altre domande sui tag switch-statement