2009-12-11 3 views
6

Est-ce que les deux extraits de code suivants permettent d'obtenir la même chose?Ces 2 énoncés sont-ils identiques?

Mon code d'origine:

if (safeFileNames != null) 
{ 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
} 
else 
{ 
    this.SafeFileNames = false; 
} 

Quelle pensée ReSharper était une meilleure idée:

this.SafeFileNames = safeFileNames != null && 
        Convert.ToBoolean(safeFileNames.Value); 

Je pense que le code ci-dessus est beaucoup plus facile à lire, aucune raison impérieuse de le changer?
Exécuterait-il plus vite, et surtout, le code fera-t-il exactement la même chose?

Aussi si vous regardez la section: Convert.ToBoolean(safeFileNames.Value);, alors sûrement cela pourrait provoquer une exception de référence nulle?

this.SafeFileNames = bool 

safeFileNames Local est un objet personnalisé fortement typé, voici la classe:

public class Configuration 
    { 
     public string Name 
     { 
      get; 
      set; 
     } 
     public string Value 
     { 
      get; 
      set; 
     } 
    } 
+3

Vous n'obtiendrez un 'NullReferenceExcepton' depuis la première partie de l'instruction 'safeFileNames! = null' court-circut dehors et vous ne frapperez jamais' Convert.ToBoolean (safeFileNames.Value) '- c'est le wa y && travaille. – Nate

+2

Cela ne provoquerait pas une exception de référence nulle à cause de l'évaluation paresseuse de C#. L'instruction && est toujours évaluée côté gauche puis côté droit. Mais si le côté gauche est faux, cela ne dérangera pas d'évaluer le côté droit, puisque le résultat logique est déjà déterminé. Donc, si safeFileNames est null alors l'appel Convert.ToBoolean n'est jamais fait. Ce genre de chose est assez courant dans le code. –

+1

Donc, si je comprends le && - si la partie gauche est fausse, elle renvoie false ... sinon elle évalue la partie droite, et renvoie le résultat de la partie droite? –

Répondre

24

Le fait que vous ayez posé la question me suggère que le premier est préféré. C'est-à-dire, il me semble que votre question implique que vous croyez que le premier code soit plus facile à comprendre, et vous n'êtes pas tout à fait sûr si le second est équivalent. L'un des principaux objectifs de la conception de logiciels est de gérer la complexité. Si cela vous déroute maintenant, cela peut aussi vous arriver plus tard, ou à quiconque appuie votre code sur la route.

+4

Ceci est une excellente réponse. – jason

+0

+1 à KISS [15] –

+0

Très bon moyen de le regarder. –

5

Les deux déclarations font exactement la même chose. Lequel utiliser est une question de préférence, mais je préfère la version de Resharper. Des pièces plus concises, moins mobiles. Plus facile de voir l'intention du code.

+0

Que faire si this.SafeFileNames est null? Essayer d'utiliser Convert.ToBoolean sur une valeur nulle provoquerait une exception de référence nulle? –

+0

@JL: la seconde clause ne serait jamais exécutée si SafeFileNames était nul – Randolpho

+0

Court-circuit pour la victoire. –

1

Ce sont les mêmes. Le & & est un opérateur de court-circuit de sorte que la seconde moitié de l'expression n'évaluera pas si safeFileNames est null.

1

Ils sont identiques. Dans la première ligne, si la première condition échoue, la seconde n'est pas évaluée. Donc vous n'obtenez pas de référence nulle. Je parie que l'IL est la même dans les deux cas.

Je préfère la deuxième version.

2

Réduit la complexité cyclomatique de votre code en utilisant la suggestion de re-découpage.

Que ce soit plus facile à lire ou non, c'est une opinion personnelle, mais je préfère la suggestion que vous a donnée le chercheur.

Ils sont identiques, et si vous voulez la lisibilité, je pourrais également suggérer les éléments suivants:

if (safeFileNames != null) 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
else 
    this.SafeFileNames = false; 

ou

this.SafeFileNames = safeFileNames != null ? Convert.ToBoolean(safeFileNames.Value) : false 
+0

Note: Le fait de supprimer des accolades quand elles sont inutiles rend le code meilleur, encore une fois, basé sur l'opinion. –

+0

@Aqutarium, votre réponse n'est pas incorrecte ou inefficace. Ce n'est pas aussi excitant que les autres, je suppose. Voter vous. –

+0

C'est une opinion, mais il vaut la peine de noter que StyleCop signalera cela comme une erreur. La cohérence est un facteur; l'autre est l'introduction d'une erreur lorsque vous ajoutez votre deuxième déclaration dans un if (sans autre) et oubliez d'ajouter vos accolades. IDE sera généralement indentation et vous informer, mais si vous utilisez Visual Notepad .... –

1

Yep ces deux déclarations vont faire la même chose, vous ne Il faut prendre des suggestions de re-sharpers comme gospel, ce qu'un homme considère comme code lisible est un autre mess de l'homme.

Il y a quelques autres façons de faire ce que vous essayez de faire qui pourrait être plus lisible, quel type de valeur est safeFileNames? Il semble que ce soit un booléen nullable?Si oui, vous pouvez simplement écrire,

this.SafeFileNames = safeFileNames.GetValueOrDefault(); 
0

Logiquement, ils sont identiques. Toute différence de performance serait probablement négligeable. Il est possible que la seconde forme se traduise par un code binaire plus efficace sur certaines plates-formes puisque la seconde forme élimine un conditionnel. Les conditions (exécution spéculative incorrecte) peuvent perturber le pipeline d'instructions de votre CPU dans un travail gourmand en CPU. Cependant, l'IL et le JITter doivent tous deux émettre un code de qualité suffisante pour que cela fasse une grande différence. Je suis d'accord avec votre sens de la lisibilité, mais je ne suppose pas que tout le monde le partage.

5

Voici IL pour les deux morceaux de code. J'ai pris votre code et créé une application de console pour jeter un oeil à l'IL. Comme vous pouvez le voir à partir de l'IL qui en résulte, une méthode (méthode2) est plus courte de 4 octets, mais l'IL qui fonctionne pour les deux est à peu près la même, donc en ce qui concerne les performances ... ne vous inquiétez pas. Ils auront tous deux la même performance. Concentrez-vous davantage sur lequel est le plus facile à lire et démontre mieux votre intention.

Mon code:

class Program 
{ 
    static void Main(string[] args) 
    { 


    } 
    public void method1() 
    { 
     bool? safeFileNames = null; 

     if (safeFileNames != null) 
     { 
      SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
     } 
     else 
     { 
      SafeFileNames = false; 
     } 
    } 
    public void method2() 
    { 
     bool? safeFileNames = null; 
     SafeFileNames = safeFileNames != null && Convert.ToBoolean(safeFileNames.Value); 
    } 
    public static bool SafeFileNames { get; set; } 
} 

L'IL pour la méthode 1:

.method public hidebysig instance void method1() cil managed 
{ 
    // Code size  42 (0x2a) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_0023 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0022: ret 
    IL_0023: ldc.i4.0 
    IL_0024: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0029: ret 
} // end of method Program::method1 

L'IL pour method2:

.method public hidebysig instance void method2() cil managed 
{ 
    // Code size  38 (0x26) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_001f 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: br.s  IL_0020 
    IL_001f: ldc.i4.0 
    IL_0020: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0025: ret 
} // end of method Program::method2 
+1

Si je pouvais donner cela plus de 1 point je le ferais, j'aime quand les gens vérifient l'IL pour déterminer les différences réelles. –

+0

+1 pour l'effort extrême, et merci beaucoup! –

+0

Semblait comme une bonne excuse pour dépoussiérer ildasm et joue autour pendant un moment :-) – jvilalta

Questions connexes