Quand est-il approprié d'utiliser une instruction de basculement (classique)? Une telle utilisation est-elle recommandée et encouragée ou devrait-elle être évitée à tout prix?
Quand est-il approprié d'utiliser une instruction de basculement (classique)? Une telle utilisation est-elle recommandée et encouragée ou devrait-elle être évitée à tout prix?
Réponses:
Voici un exemple où cela serait 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;
}
Ce genre de chose (où un cas inclut l'autre) est plutôt rare, je pense, c'est pourquoi certaines langues plus récentes ne permettent pas la substitution ou nécessitent une syntaxe spéciale pour cela.
// INTENTIONAL FALL THROUGH HERE
commentaire tout en majuscules requis .
GetItemsForLevel(Info)
appel GetItemsForLevel(Warning)
, etc.
Je les utilise lorsque certaines fonctionnalités doivent être appliquées pour plusieurs valeurs. Par exemple, supposons que vous ayez un objet avec une propriété appelée operationCode. Si le code est égal à 1, 2, 3 ou 4, vous souhaitez démarrer OperationX (). Si c'est 5 ou 6, vous voulez démarrerOperationY () et 7 vous démarrezOperationZ (). Pourquoi avoir 7 cas complets avec des fonctionnalités et des pauses lorsque vous pouvez utiliser des raccourcis
Je pense que c'est complètement valable dans certaines situations, surtout si cela évite 100 déclarations if-else. =)
switch
avec plusieurs case
s liés au même code. C'est différent d'une erreur, où l'exécution de l'un se case
poursuit dans le suivant en raison de l'absence d'un break
entre eux.
Les cas de chute sont parfaitement bien. Je trouve souvent qu'une énumération est utilisée dans de nombreux endroits et que lorsque vous n'avez pas besoin de différencier certains cas, il est plus facile d'utiliser la logique de substitution.
Par exemple (notez les commentaires explicatifs):
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;
}
}
Je trouve ce type d'utilisation parfaitement acceptable.
case X: case Y: doSomething()
et case X: doSomething(); case Y: doAnotherThing()
. Dans le premier, l'intention est assez explicite, tandis que dans le second, la chute peut être intentionnelle ou non. D'après mon expérience, le premier exemple ne déclenche jamais aucun avertissement dans les compilateurs / analyseurs de code, tandis que le second le fait. Personnellement, je n'appellerais le deuxième exemple que "tomber" - mais je ne suis pas sûr d'une définition "officielle".
Ça dépend de:
Les deux principaux problèmes associés au fait de laisser un cas passer au suivant sont les suivants:
Cela rend votre code dépendant de l'ordre des déclarations de cas. Ce n'est pas le cas si vous ne vous trompez jamais, et cela ajoute un degré de complexité souvent indésirable.
Il n'est pas évident que le code d'un cas inclut le code d'un ou de plusieurs cas ultérieurs.
Certains endroits interdisent explicitement de passer. Si vous ne travaillez pas dans un tel endroit, et si vous êtes à l'aise avec la pratique, et si la violation du code en question ne causera aucune souffrance réelle, ce ne sera peut-être pas la pire chose au monde. Si vous le faites, assurez-vous de mettre un commentaire accrocheur à proximité pour avertir ceux qui viendront plus tard (y compris l'avenir).
Voici un exemple rapide (certes incomplet (pas de traitement spécial de l'année bissextile)) de chute qui me simplifie la vie:
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;
}
Si je ressens le besoin de passer d'un cas à l'autre (rare, certes), je préfère être très explicite et goto case
, bien sûr, cela suppose que votre langue le supporte.
Parce que tomber à travers est si rare et très facile à ignorer lors de la lecture de code, je pense qu'il est approprié d'être explicite - et un goto, même s'il s'agit d'un cas, devrait se démarquer comme un pouce endolori.
Cela permet également d'éviter les bogues qui peuvent survenir lors de la réorganisation des instructions de cas.