Quel est l'avantage / inconvénient de l'utilisation d'une switch
déclaration par rapport à un if/else
en C #. Je ne peux pas imaginer qu'il y ait une grande différence, à part peut-être l'apparence de votre code.
Y a-t-il une raison pour laquelle l'IL résultant ou les performances d'exécution associées seraient radicalement différentes?
En relation: Qu'est-ce qui est plus rapide, activer la chaîne ou le type elseif?
c#
.net
switch-statement
Matthew M. Osborn
la source
la source
Réponses:
L'instruction SWITCH produit uniquement le même assembly que les IF en mode débogage ou compatibilité. Dans la version, il sera compilé dans la table de saut (via l'instruction 'switch' MSIL) - qui est O (1).
C # (contrairement à de nombreux autres langages) permet également d'activer les constantes de chaîne - et cela fonctionne un peu différemment. Il n'est évidemment pas pratique de construire des tables de saut pour des chaînes de longueurs arbitraires, donc le plus souvent un tel commutateur sera compilé en pile de FI.
Mais si le nombre de conditions est suffisamment grand pour couvrir les frais généraux, le compilateur C # créera un objet HashTable, le remplira avec des constantes de chaîne et fera une recherche sur cette table suivie d'un saut. La recherche de table de hachage n'est pas strictement O (1) et a des coûts constants notables, mais si le nombre d'étiquettes de cas est grand, il sera beaucoup plus rapide que de comparer à chaque constante de chaîne dans les FI.
Pour résumer, si le nombre de conditions est supérieur à 5 ou plus, préférez SWITCH à IF, sinon utilisez ce qui semble mieux.
la source
En général (compte tenu de tous les langages et de tous les compilateurs), une instruction switch PEUT PARFOIS être plus efficace qu'une instruction if / else, car il est facile pour un compilateur de générer des tables de saut à partir d'instructions switch. Il est possible de faire la même chose pour les instructions if / else, étant donné les contraintes appropriées, mais c'est beaucoup plus difficile.
Dans le cas de C #, cela est également vrai, mais pour d'autres raisons.
Avec un grand nombre de chaînes, l'utilisation d'une instruction switch présente un avantage significatif en termes de performances, car le compilateur utilise une table de hachage pour implémenter le saut.
Avec un petit nombre de cordes, les performances entre les deux sont les mêmes.
En effet, dans ce cas, le compilateur C # ne génère pas de table de saut. Au lieu de cela, il génère MSIL qui est équivalent aux blocs IF / ELSE.
Il existe une instruction MSIL "instruction de commutation" qui, lorsqu'elle est jitted, utilisera une table de saut pour implémenter une instruction de commutation. Cependant, cela ne fonctionne qu'avec des types entiers (cette question concerne les chaînes).
Pour un petit nombre de chaînes, il est plus efficace pour le compilateur de générer des blocs IF / ELSE que d'utiliser une table de hachage.
Lorsque j'ai remarqué cela à l'origine, j'ai fait l'hypothèse que, comme les blocs IF / ELSE étaient utilisés avec un petit nombre de chaînes, le compilateur faisait la même transformation pour un grand nombre de chaînes.
C'était faux. 'IMA' a eu la gentillesse de me le signaler (enfin ... il n'était pas gentil à ce sujet, mais il avait raison, et j'avais tort, ce qui est important)
J'ai également fait une supposition à propos de l'absence d'une instruction "switch" dans MSIL (je me suis dit, s'il y avait une primitive switch, pourquoi ne l'utilisaient-ils pas avec une table de hachage, donc il ne devait pas y avoir de primitive switch. ...). C'était à la fois faux et incroyablement stupide de ma part. Encore une fois, «IMA» me l'a fait remarquer.
J'ai fait les mises à jour ici parce que c'est le post le mieux noté et la réponse acceptée.
Cependant, je l'ai fait Community Wiki parce que je pense que je ne mérite pas le REP pour avoir tort. Si vous en avez l'occasion, veuillez voter pour le poste de 'ima'.
la source
Trois raisons de préférer
switch
:Un compilateur ciblant le code natif peut souvent compiler une instruction switch dans une branche conditionnelle plus un saut indirect alors qu'une séquence de
if
s nécessite une séquence de branches conditionnelles . En fonction de la densité des cas, de nombreux articles savants ont été rédigés sur la manière de compiler efficacement les déclarations de cas; certains sont liés depuis la page du compilateur lcc . (Lcc avait l'un des compilateurs les plus innovants pour les commutateurs.)Une instruction switch est un choix parmi des alternatives mutuellement exclusives et la syntaxe de switch rend ce flux de contrôle plus transparent pour le programmeur, puis un nid d'instructions if-then-else.
Dans certaines langues, notamment ML et Haskell, le compilateur vérifie si vous avez omis des cas . Je considère cette fonctionnalité comme l'un des principaux avantages de ML et Haskell. Je ne sais pas si C # peut le faire.
Une anecdote: lors d'une conférence qu'il a donnée sur la réception d'un prix pour l'ensemble de sa carrière, j'ai entendu Tony Hoare dire que de toutes les choses qu'il a faites dans sa carrière, il y en avait trois dont il était le plus fier:
case
déclaration)Je ne peux pas imaginer vivre sans
switch
.la source
Le compilateur va optimiser à peu près tout dans le même code avec des différences mineures (Knuth, n'importe qui?).
La différence est qu'une instruction switch est plus propre que quinze si les instructions else sont liées ensemble.
Les amis ne laissent pas les amis empiler les instructions if-else.
la source
En fait, une instruction switch est plus efficace. Le compilateur l'optimisera dans une table de recherche où avec les instructions if / else il ne peut pas. L'inconvénient est qu'une instruction switch ne peut pas être utilisée avec des valeurs variables.
Vous ne pouvez pas faire:
ça doit être
la source
Je n'ai vu personne d'autre soulever le point (évident?) Que l'avantage d'efficacité supposé de l'instruction switch dépend du fait que les différents cas sont à peu près également probables. Dans les cas où l'une (ou quelques-unes) des valeurs sont beaucoup plus probables, l'échelle if-then-else peut être beaucoup plus rapide, en s'assurant que les cas les plus courants sont d'abord vérifiés:
Ainsi, par exemple:
contre
Si x vaut zéro dans 90% des cas, le code "if-else" peut être deux fois plus rapide que le code basé sur le commutateur. Même si le compilateur transforme le «commutateur» en une sorte de goto intelligent piloté par table, il ne sera toujours pas aussi rapide que de simplement vérifier zéro.
la source
switch
compatibles, l'switch
instruction est meilleure (plus lisible, parfois plus rapide). Si vous savez qu'un cas est beaucoup plus probable, vous pouvez le retirer pour former une constructionif
-else
-switch
et s'il est sensiblement plus rapide , laissez- le dedans . (Répétez, si nécessaire.) IMO qui est encore raisonnablement lisible. Si leswitch
dégénère et devient trop petit, un regex-replace fera la plupart du travail de le transformer en uneelse if
chaîne.souvent, il sera plus joli, c'est-à-dire qu'il sera plus facile de comprendre ce qui se passe. Étant donné que les performances seront au mieux extrêmement minimes, la vue du code est la différence la plus importante.
Donc, si le if / else semble meilleur, utilisez-le, sinon utilisez une instruction switch.
la source
Sujet secondaire, mais je m'inquiète souvent (et je le vois plus souvent)
if
/else
etswitch
déclaration devient trop volumineuse avec trop de cas. Celles-ci nuisent souvent à la maintenabilité.Les coupables communs comprennent:
Pour corriger:
la source
Selon ce lien, la comparaison IF vs Switch du test d'itération en utilisant l'instruction switch et if, est similaire à 1 000 000 000 d'itérations, le temps pris par l' instruction Switch = 43,0s et par l' instruction If = 48,0s
Qui est littéralement 20833333 itérations par seconde. Donc, devons-nous vraiment nous concentrer davantage,
PS: Juste pour connaître la différence de performances pour une petite liste de conditions.
la source
Si vous utilisez simplement l'instruction if ou else, la solution de base utilise la comparaison? opérateur
Vous pouvez faire la routine ou dans un commutateur
la source
Cela ne répond pas réellement à votre question, mais étant donné qu'il y aura peu de différence entre les versions compilées, je vous exhorte à écrire votre code d'une manière qui décrit le mieux vos intentions. Non seulement il y a de meilleures chances que le compilateur fasse ce que vous attendez, mais il sera plus facile pour les autres de maintenir votre code.
Si votre intention est de brancher votre programme en fonction de la valeur d'une variable / attribut, alors une instruction switch représente le mieux cette intention.
Si votre intention est de brancher votre programme en fonction de différentes variables / attributs / conditions, alors une chaîne if / else if représente le mieux cette intention.
J'accorderai que cody a raison à propos des gens qui oublient la commande break, mais presque aussi souvent je vois des gens faire des blocs compliqués où ils se trompent {}, donc les lignes qui devraient être dans l'instruction conditionnelle ne le sont pas. C'est l'une des raisons pour lesquelles j'inclus toujours {} dans mes instructions if, même s'il y a une ligne. Non seulement il est plus facile à lire, mais si j'ai besoin d'ajouter une autre ligne au conditionnel, je ne peux pas oublier de l'ajouter.
la source
Question d'intérêt. Cela est arrivé il y a quelques semaines au travail et nous avons trouvé une réponse en écrivant un exemple d'extrait et en le visualisant dans .NET Reflector (le réflecteur est génial !! je l'adore).
Voici ce que nous avons découvert: une instruction switch valide pour autre chose qu'une chaîne est compilée en IL en tant qu'instruction switch. Cependant SI c'est une chaîne, elle est réécrite en if / else if / else en IL. Donc, dans notre cas, nous voulions savoir comment les instructions de commutateur comparent les chaînes, par exemple, sont sensibles à la casse, etc. et le réflecteur nous a rapidement donné une réponse. C'était utile de savoir.
Si vous souhaitez effectuer une comparaison sensible à la casse sur les chaînes, vous pouvez utiliser une instruction switch car elle est plus rapide que d'effectuer un String.Compare dans un if / else. (Edit: Read What is quicker, switch on string or elseif on type? For some actual performance tests) Cependant, si vous vouliez faire une insensibilité à la casse, il est préférable d'utiliser un if / else car le code résultant n'est pas joli.
La meilleure règle d'or consiste à utiliser des instructions switch si cela a du sens (sérieusement), par exemple:
Si vous devez manipuler la valeur à alimenter dans l'instruction switch (créer une variable temporaire contre laquelle basculer), vous devriez probablement utiliser une instruction de contrôle if / else.
Une mise à jour:
Il est en fait préférable de convertir la chaîne en majuscules (par exemple
ToUpper()
) car cela a été apparemment il y a d'autres optimisations que le compilateur juste à temps peut faire comme par rapport auToLower()
. Il s'agit d'une micro optimisation, mais en boucle serrée, cela pourrait être utile.Une petite note:
Pour améliorer la lisibilité des instructions switch, essayez ce qui suit:
la source
L'instruction switch est certainement la plus rapide puis un if if if. Il y a des tests de vitesse qui ont été fournis par BlackWasp
http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx
--Vérifiez-le
Mais cela dépend fortement des possibilités que vous essayez de prendre en compte, mais j'essaie d'utiliser une instruction switch dans la mesure du possible.
la source
Pas seulement C #, mais tous les langages basés sur C, je pense: parce qu'un commutateur est limité aux constantes, il est possible de générer du code très efficace en utilisant un "jump table". Le cas C est vraiment un bon vieux GOTO calculé FORTRAN, mais le cas C # est toujours testé contre une constante.
Ce n'est pas le cas que l'optimiseur pourra faire le même code. Considérez, par exemple,
Parce que ce sont des booléens composés, le code généré doit calculer une valeur et un court-circuit. Considérons maintenant l'équivalent
Cela peut être compilé en
parce que vous dites implicitement au compilateur qu'il n'a pas besoin de calculer les tests OR et d'égalité.
la source
Mon professeur CS a suggéré de ne pas changer de déclaration, car si souvent les gens oublient la pause ou l'utilisent incorrectement. Je ne peux pas me souvenir exactement de ce qu'il a dit, mais quelque chose dans le sens où en regardant une base de code séminale qui montrait des exemples de la déclaration switch (il y a des années) avait aussi des tonnes d'erreurs.
la source
Quelque chose que je viens de remarquer est que vous pouvez combiner les instructions if / else et switch! Très utile pour vérifier les conditions préalables.
la source
Je pense que Switch est plus rapide que si des conditions comme voir s'il existe un programme comme:
Écrivez un programme pour entrer n'importe quel nombre (entre 1 - 99) et vérifiez qu'il se trouve dans quel emplacement a) 1 - 9 puis emplacement un b) 11 - 19 puis emplacement deux c) 21-29 puis emplacement trois et ainsi de suite jusqu'à 89- 99
Ensuite, si vous devez faire de nombreuses conditions, mais que vous devez taper le boîtier de commutation de fils
ce sera si facile
Il existe également de nombreux autres exemples!
la source
une instruction switch est fondamentalement une comparaison pour l'égalité. Les événements clavier ont un grand avantage sur les instructions switch lorsqu'ils ont du code facile à écrire et à lire, alors une instruction if elseif le ferait, manquer un {bracket} pourrait également devenir problématique.
Une instruction if elseif est idéale pour plus d'une solution si (theAmountOfApples est supérieur à 5 && theAmountOfApples est inférieur à 10) enregistrez vos pommes ailleurs si (theAmountOfApples est supérieur à 10 || theAmountOfApples == 100) vendez vos pommes. Je n'écris pas c # ou c ++ mais je l'ai appris avant d'apprendre java et ce sont des langues proches.
la source
Un inconvénient possible des déclarations de commutateur est son manque de conditions multiples. Vous pouvez avoir plusieurs conditions pour les instructions if (else) mais pas plusieurs cases avec des conditions différentes dans un commutateur.
Les instructions de commutation ne conviennent pas aux opérations logiques au-delà de la portée des équations / expressions booléennes simples. Pour ces équations / expressions booléennes, il convient parfaitement mais pas pour d'autres opérations logiques.
Vous avez beaucoup plus de liberté avec la logique disponible dans les instructions If, mais la lisibilité peut en souffrir si l'instruction If devient difficile à manier ou est mal gérée.
Les deux ont leur place selon le contexte de ce à quoi vous êtes confronté.
la source