Y a-t-il une différence significative entre l'utilisation de if/else et switch-case dans C#?

Quel est l'avantage/inconvénient de l'utilisation d'un switch déclaration contre un if/else en C#. Je ne peux pas imaginer qu'il y ait une telle différence, à part peut-être l'apparence de votre code.

y a-t-il une raison pour laquelle L'IL résultante ou la performance d'exécution associée serait radicalement différente?

Related: Ce qui est plus rapide, basculer sur la chaîne ou elseif sur type?

182
demandé sur Community 2008-12-28 03:16:47

20 réponses

L'instruction de commutation

ne produit que le même assemblage que L'IFs en mode de débogage ou de compatibilité. Dans release, il sera compilé dans jump table (via MSIL 'switch' statement)- qui est O(1).

c# (contrairement à beaucoup d'autres langues) 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 sauts pour des chaînes de longueurs arbitraires, de sorte que le plus souvent un tel switch sera compilé dans une pile de fi.

mais si le nombre de conditions est assez grand pour couvrir les frais généraux, C# compiler créera un objet HashTable, le peuplera de constantes de chaîne et fera une recherche sur cette table suivie de saut. Hashtable lookup 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 IFs.

pour résumer, si le nombre de conditions est plus de 5 ou plus, préfèrent passer SI, AUTREMENT utiliser ce qui semble mieux.

281
répondu ima 2017-02-05 05:19:30

en général (en considérant toutes les langues et 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 énoncés if / else, étant donné les contraintes appropriées, mais c'est beaucoup plus difficile.

Dans le cas de C#, c'est vrai aussi, mais pour d'autres raisons.

Avec un grand nombre de strings, il y a un avantage de performance significatif à utiliser une instruction switch, parce que le compilateur utilisera une table de hachage pour implémenter le saut.

avec un petit nombre de cordes, la performance entre les deux est la même.

c'est parce que 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 à If / ELSE blocks.

Il y a un "switch" instruction MSIL qu'en cas de problème, une table de saut sera utilisée pour mettre en œuvre une instruction de commutation. Il fonctionne seulement avec les types entiers, cependant (cette question pose des chaînes de caractères).

pour un petit nombre de chaînes, il est plus efficace pour le compilateur de générer si / ELSE bloque alors il est d'utiliser une table de hachage.

quand j'ai remarqué cela, j'ai fait l'hypothèse que si / ELSE blocks étaient utilisés avec un petit nombre de chaînes, que le compilateur faisait la même chose transformation pour un grand nombre de cordes.

C'était mal. "IMA" a eu la gentillesse de me le signaler (bien...il n'était pas du genre à ce sujet, mais il avait raison et j'avais tort, ce qui est l'essentiel)

j'ai également fait une hypothèse à tête d'os sur 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 doit pas y avoir une primitive switch.... ). Ce fut à la fois mal, et incroyablement stupide de ma part. "IMA" me l'a encore fait remarquer.

j'ai fait les mises à jour ici parce que c'est le poste le mieux noté, et la réponse acceptée.

cependant, je l'ai fait Wiki communautaire parce que je pense que je ne mérite pas le REP pour avoir tort. Si vous en avez l'occasion, veuillez voter " ima " poste.

45
répondu Scott Wisniewski 2008-12-29 00:13:42

trois raisons de préférer le switch :

  • un compilateur ciblant le code natif peut souvent compiler un État de commutation dans une branche conditionnelle plus un saut indirect tandis qu'une séquence de if s nécessite une séquence de branches conditionnelles . En fonction de la densité des cas, un grand nombre de documents savants ont été écrits sur la façon de compiler efficacement des déclarations de cas; certains sont liés à partir de la page du compilateur lcc . (Lcc avait l'un des compilateurs les plus innovants pour les commutateurs.)

  • une instruction de commande est un choix parmi des alternatives mutuellement exclusives et la syntaxe de commande rend ce flux de commande plus transparent pour le programmeur puis un nid d'instructions if-then-else.

  • dans certains langues, y compris certainement ML et Haskell, le compilateur vérifie pour voir si vous avez omis des cas . Je considère cette caractéristique comme l'un des principaux avantages de ML et Haskell. Je ne sais pas si C# peut faire ça.

une anecdote: lors d'une conférence qu'il a donnée sur le fait de recevoir un prix pour l'ensemble de ses réalisations, 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:

  • Inventer Quicksort
  • Inventer l'instruction switch (Tony appelé le case déclaration)
  • début et fin de sa carrière dans l'industrie

je ne peut pas imaginer de vivre sans switch .

16
répondu Norman Ramsey 2011-08-13 01:46:34

en fait, une instruction de commutation est plus efficace. Le compilateur d'optimiser à une table où avec 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:

switch(variable)
{
   case someVariable
   break;
   default:
   break;
}

il a à être

switch(variable)
{
  case CONSTANT_VALUE;
  break;
  default:
  break;
}
14
répondu kemiller2002 2008-12-28 13:57:18

le compilateur va optimiser à peu près tout dans le même code avec des différences mineures (Knuth, quelqu'un?).

la différence est qu'une instruction switch est plus propre que quinze si d'autres instructions sont attachées ensemble.

les amis ne laissent pas leurs amis empiler des déclarations if-else.

13
répondu Will 2008-12-28 00:22:37

Je n'ai vu personne d'autre soulever la (évidente?) soulignent que l'avantage supposé de l'efficacité de la déclaration de l'interrupteur dépend du fait que les différents cas sont à peu près également probables. Dans les cas où 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 vérifiés en premier:

ainsi, par exemple:

if (x==0) then {
  // do one thing
} else if (x==1) {
  // do the other thing
} else if (x==2) {
  // do the third thing
}

vs

switch(x) {
  case 0: 
         // do one thing
         break;
  case 1: 
         // do the other thing
         break;
  case 2: 
         // do the third thing
         break;
}

Si x est zéro 90% du temps, le code" if-else " peut être deux fois plus rapide que le code basé sur le commutateur. Même si le compilateur transforme le "switch" en une sorte de goto intelligent piloté par table, il ne sera pas aussi rapide que de simplement vérifier zéro.

10
répondu Mark Bessey 2009-10-15 22:32:16

souvent, il aura l'air mieux - ie sera plus facile de comprendre ce qui se passe. Compte tenu de l'avantage de performance sera extrêmement minime au mieux, 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.

7
répondu gbjbaanb 2008-12-28 00:22:54

sujet secondaire, mais je m'inquiète souvent de (et le plus souvent voir) if / else et switch déclaration obtenir beaucoup trop grand avec trop de cas. Cela nuit souvent à la maintenabilité.

les coupables courants comprennent:

  1. d'en Faire trop à l'intérieur de plusieurs instructions if
  2. plus d'énoncés de cas qu'il est humainement possible d'analyser
  3. trop de conditions dans l'évaluation de la fi pour savoir ce qui est recherché

pour fixer:

  1. extrait pour reformage de la méthode.
  2. utilisez un dictionnaire avec des pointeurs de méthode au lieu d'un boîtier, ou utilisez un IoC pour plus de configurabilité. Méthode usines peuvent également être utiles.
  3. extraire les conditions à leur propre méthode
4
répondu Chris Brandsma 2008-12-28 05:32:05

si vous n'utilisez que si ou bien si la solution de base utilise la comparsion ? exploitant

(value == value1) ? (type1)do this : (type1)or do this;

Vous pouvez faire à la ou de routine dans un interrupteur

switch(typeCode)
{
   case TypeCode:Int32:
   case TypeCode.Int64:
     //dosomething here
     break;
   default: return;
}
3
répondu Robert W. 2010-08-02 02:10:49

cela ne répond pas vraiment à votre question, mais étant donné qu'il y aura peu de différence entre les versions compilées, je vous conseille vivement d'écrire votre code d'une manière qui décrit le mieux vos intentions. Non seulement il y a une meilleure chance de le compilateur fait ce que vous attendez, mais il sera plus facile pour les autres de maintenir votre code.

si votre intention est de relier votre programme en fonction de la valeur d'une variable/attribut, alors un État de commutation est préférable représente cette intention.

si votre intention est de relier votre programme en fonction de variables/attributs/conditions différentes, alors une chaîne if/else if représente le mieux cette intention.

je concède que cody a raison au sujet des gens qui oublient la commande de rupture, mais presque aussi souvent je vois des gens faire compliqué si les blocs où ils obtiennent le { } faux, donc les lignes qui devraient être dans la déclaration conditionnelle ne sont pas. C'est une des raisons pour lesquelles je toujours inclure { } sur mon si les déclarations, même si il ya une ligne. Non seulement est-il plus facile à lire, mais si j'ai besoin d'ajouter une autre ligne au conditionnel, je ne peux pas oublier de l'ajouter.

2
répondu dj_segfault 2008-12-28 06:21:32

l'instruction de commutation est certainement le plus rapide puis un SI AUTREMENT si. Il ya speedtest qui ont été fournis sur elle par BlackWasp

http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx

-- Check it out

Mais dépend fortement les possibilités que vous essayez de compte, mais j'essaie d'utiliser une instruction switch à chaque fois que possible.

2
répondu sleath 2011-10-20 01:20:06

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 une"table de saut". Le cas C est vraiment un bon vieux GOTO Fortran calculé, mais le cas C# est toujours des tests contre une constante.

ce n'est pas le cas que l'optimiseur sera capable de faire le même code. Considérez, par exemple,

if(a == 3){ //...
} else if (a == 5 || a == 7){ //...
} else {//...
}

parce que ce sont des booléens composés, le code généré a pour calculer une valeur, et courtcircuit. Maintenant, considérez l'équivalent

switch(a){
   case 3: // ...
    break;
   case 5:
   case 7: //...
    break;
   default: //...
}

peut être compilé en

BTABL: *
B3:   addr of 3 code
B5:
B7:   addr of 5,7 code
      load 0,1 ino reg X based on value
      jump indirect through BTABL+x

parce que vous dites implicitement au compilateur qu'il n'a pas besoin de calculer les tests OR et equality.

1
répondu Charlie Martin 2009-10-15 22:58:12

question D'intérêt. C'est arrivé il y a quelques semaines au travail et nous avons trouvé une réponse en écrivant un exemple et en le regardant dans le réflecteur. Net (Le réflecteur est génial!! je l'aime).

c'est Ce que nous avons découvert: Valide instruction switch pour autre chose qu'une chaîne est compilé pour IL comme une instruction switch. Cependant, si c'est une chaîne de caractères, elle est réécrite comme si/else if/else in IL. Dans notre cas, nous avons voulu savoir comment comparer les instructions switch E. g is sensible à la casse etc. et le réflecteur nous a rapidement donné une réponse. C'était utile de le savoir.

si vous voulez faire une comparaison sensible à la casse sur les chaînes, alors vous pourriez utilisez une instruction switch car elle est plus rapide que l'exécution d'une chaîne.Comparez dans un if/else. (Edit: Lire Ce qui est plus rapide, basculer sur la chaîne ou elseif sur type? pour certains tests de performance réels) cependant si vous vouliez faire un cas-insensible il est alors préférable d'utiliser un if / else car le code résultant n'est pas joli.

switch (myString.ToLower())
{
  // not a good solution
}

la meilleure règle de base est d'utiliser des instructions d'interrupteur si cela a un sens (sérieusement), E. g:

  • il améliore la lisibilité de votre code
  • vous comparez une gamme de valeurs (float, int) ou un enum

si vous avez besoin de manipuler la valeur pour alimenter dans la déclaration de commutateur (créer un variable temporaire pour basculer contre) alors 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 majuscule (par exemple ToUpper() ) car cela a été apparemment il y a d'autres optimisations que le compilateur juste-à-temps peut faire comme par rapport au ToLower() . C'est un micro-optimisation, cependant dans une boucle serrée, il pourrait être utile.


une petite note latérale:

pour améliorer la lisibilité des instructions d'interrupteur, essayez ce qui suit:

  • placer la branche la plus probable en premier, c'est-à-dire la plus accessible
  • si elles sont toutes susceptibles de se produire, les énumérer dans l'ordre alphabétique de sorte qu'il soit plus facile de les trouver.
  • n'utilisez jamais le catch-all par défaut pour la dernière condition restante, c'est paresseux et ça causera des problèmes plus tard dans la vie du code.
  • utilisez le "catch-all" par défaut pour affirmer une condition inconnue même si elle est très improbable qu'elle se produise. c'est ce qu'affirme sont bons pour.
1
répondu Dennis 2017-05-23 12:02:48

selon ce lien, IF vs Switch la comparaison de l'essai d'itération à l'aide de l'interrupteur et de l'instruction if, est comme pour 1.000.000.000 itérations, le temps pris par Switch instruction= 43.0 s & par If instruction = 48.0 s

qui est littéralement 20833333 itérations par seconde, donc, devrait-on vraiment avoir besoin de se concentrer plus,

P. S: juste pour connaître la différence de performance pour une petite liste de conditions.

1
répondu Bretfort 2013-10-27 06:13:39

mon professeur cs a suggéré de ne pas vous changer de déclarations puisque si souvent les gens ont oublié la pause ou de l'utiliser incorrectement. Je ne me souviens pas exactement de ce qu'il a dit, mais quelque chose dans le sens où en regardant une base de code séminal qui montrait des exemples de la déclaration de switch (il y a des années) il y avait aussi des tonnes d'erreurs.

0
répondu 2008-12-28 00:45:37

quelque chose que je viens de remarquer est que vous pouvez combiner si/else et échanger des déclarations! Très utile pour vérifier les conditions préalables.

if (string.IsNullOrEmpty(line))
{
    //skip empty lines
}
else switch (line.Substring(0,1))
{
    case "1":
        Console.WriteLine(line);
        break;
    case "9":
        Console.WriteLine(line);
        break;
    default:
        break;
}
0
répondu Even Mien 2009-10-02 13:48:25

Je Pense Que L'Interrupteur Est Plus Rapide Que Si Les Conditions Comme Voir S'il y a un programme comme:

Ecrire un programme pour entrer n'importe quel nombre (entre 1 – 99) et vérifier c'est dans quelle fente a) 1 – 9 puis la fente un b) 11-19 puis la fente deux c) 21-29 puis la fente trois et ainsi de suite jusqu'à 89-99

puis sur Si vous avez à faire de nombreuses Conditions, mais son cas de commutateur, vous devez juste taper

Switch ( n /10 )

et sur le cas 0 = 1-9, cas 1 = 11-19 et ainsi de suite

il en sera Ainsi Facile

Il Y A Beaucoup Plus De Tels Exemples Aussi!

0
répondu removed 2014-08-29 15:52:42

une instruction switch bref c'est une comparaison pour l'égalité. les évènements de clavier ont un grand avantage par rapport à la déclaration switch lorsqu'il est facile d'écrire et de lire du code, alors une déclaration if elseif le ferait, manquer un {bracket} pourrait aussi être troublant.

char abc;
switch(abc)
{
case a: break;
case b: break;
case c: break;
case d: break;
}

et si ElseIf statement est grand pour plus d'une solution si (theAmountOfApples est plus grand que 5 & & theAmountOfApples est moins que 10) sauver vos pommes else if(theAmountOfApples est supérieure à 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.

0
répondu Geen 2015-04-25 02:07:06

je sais que ce n'est pas exactement la question mais je dois vraiment souligner que lorsque vous pensez à l'efficacité à ce niveau, vous pourriez avoir besoin de plus d'abstraction dans votre code. Vous n'aurez plus besoin de basculer cas, surtout si elle contient la logique. (mon exemple en php).

    $feeMapping = [
        1000 => 1,
        2000 => 2,
        3000 => 3,
        4000 => 4,
        5000 => 5,
        6000 => 6,
        7000 => 7
    ];

    function findFee($feeMapping, $amount) {
        foreach ($feeMapping as $fee => $value) {
            if ($value >= $amount) {
                return $fee;
            }
        }

        return 7;
    }

    $feeValue = findFee($feeMapping, 200);

regardez maintenant la redondance du code similaire!

    if ($amount >= 1000) {
        return 1;
    } elseif ($amount >= 2000) {
        return 2;
    } elseif ($amount >= 3000) {
        return 3;
    } elseif ($amount >= 4000) {
        return 4;
    } elseif ($amount >= 5000) {
        return 5;
    } elseif ($amount >= 6000) {
        return 6;
    } else {
        return 7;
    }
0
répondu SinisterGlitch 2016-04-05 20:04:45

L'un des inconvénients possibles des énoncés d'interrupteurs est l'absence de conditions multiples. Vous pouvez avoir plusieurs conditions pour les instructions if (else) mais pas plusieurs cas avec différentes conditions dans un commutateur.

Les énoncés 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 est éminemment approprié, mais pas pour d'autres opérations logiques.

vous avez beaucoup plus de liberté avec la logique disponible dans les déclarations si mais la lisibilité peut souffrir si la déclaration si devient lourde ou est mal traitée.

les deux ont leur place selon le contexte de ce à quoi vous êtes confrontés.

0
répondu Neil Meyer 2017-06-19 09:43:43