Compiler le code suivant.
public static int Main(string[] args)
{
switch (args[0])
{
case "x": return 1;
case "y": return 2;
case "z": return 3;
}
return 0;
}
Maintenant, utilisez un Réflecteur ou ILDASM pour examiner le IL le compilateur C# génère. Continuez à ajouter des cas de déclarations et de décompilation et d'observer le résultat.
- Si le nombre de cas annuels est petit, puis le compilateur émet une séquence de comparaison d'égalité.
- Si le nombre de cas annuels est grand alors le compilateur émet un
Dictionary
de recherche.
J'ai été en utilisant le C# 3.0 compilateur et j'ai observé que les changements de stratégie à 7 cas de déclarations. Je soupçonne que vous verrez quelque chose de similaire avec C# 4.0 et d'autres.
Mise à jour:
Je tiens à souligner que vous pourrez voir les appels d' Dictionary.Add
dans le IL sortie où elle est la construction du dictionnaire pour les utiliser plus tard. Ne vous laissez pas berner en pensant que ce qui se passe à chaque fois. Le compilateur est en fait la génération d'un distinct statique de la classe et de faire une ligne initialisation statique d'elle. Accorder une attention particulière à l'instruction à L_0026. Si la classe est déjà initialisé alors la branche va ignorer l' Add
des appels.
L_0021: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> <PrivateImplementationDetails>{816396DD-F271-4C12-83D0-CC9C9CD67AD6}::$$method0x6000001-1
L_0026: brtrue.s L_0089
L_0028: ldc.i4.7
L_0029: newobj instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor(int32)
L_002e: dup
L_002f: ldstr "x"
L_0034: ldc.i4.0
L_0035: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
L_003a: dup
L_003b: ldstr "y"
L_0040: ldc.i4.1
L_0041: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
L_0046: dup
L_0047: ldstr "z"
L_004c: ldc.i4.2
L_004d: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
Notez également que le dictionnaire contient en fait une carte de la chaîne d'origine à un entier. Cet entier est utilisé pour formuler un interrupteur séparé en IL.
L_0089: volatile.
L_008b: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> <PrivateImplementationDetails>{816396DD-F271-4C12-83D0-CC9C9CD67AD6}::$$method0x6000001-1
L_0090: ldloc.2
L_0091: ldloca.s CS$0$0002
L_0093: call instance bool [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::TryGetValue(!0, !1&)
L_0098: brfalse.s L_00da
L_009a: ldloc.3
L_009b: switch (L_00be, L_00c2, L_00c6, L_00ca, L_00ce, L_00d2, L_00d6)
L_00bc: br.s L_00da
L_00be: ldc.i4.1
L_00bf: stloc.1
L_00c0: br.s L_00de
L_00c2: ldc.i4.2
L_00c3: stloc.1
L_00c4: br.s L_00de
L_00c6: ldc.i4.3
Mise à jour 2:
Pour ce qu'il vaut VB.NET ne semble pas avoir ce même optimisation pour son Select
construire.