2011-02-10 4 views
1

Depuis que jeQuoi de mieux: id ?? 0 == 0 ou id == null || id == 0?

public class Foo 
{ 
    public int? Id { get; set; } 
} 

Quoi de mieux

if ((Id ?? 0) == 0) {} 

ou

if (Id == null || Id == 0) 

?

+2

qui est plus lisible?> –

+0

depuis que vous avez tagué votre question avec "performance" - voulez-vous dire "meilleur" en termes de performance ou en termes de lisibilité? –

+0

Vous devriez toujours essayer de tracer votre question autant que possible. Lorsque vous demandez «quoi de mieux», il est utile de décrire le type d'échelle que vous comparez. c'est à dire. "X semble-t-il mieux que Y" ou "X tourne-t-il plus vite que Y" ou "X utilisera-t-il plus de mémoire que Y", etc. Personnellement j'aime les bananes, c'est beaucoup mieux que n'importe lequel de vos exemples. –

Répondre

4

Je recommande le deuxième. C'est plus lisible.

Et comme je l'ai remarqué, moins de personnes connaissent l'opérateur ??.

+2

+1: D'accord. Du point de vue de la lisibilité, le second est supérieur, et je ne pense pas que la performance soit un problème ici. Les deux seront assez rapides. –

+2

Je suis toujours d'accord que le second est plus lisible. Mais je n'achète pas (manque de) familiarité avec '??' comme argument. Si vous ne connaissez pas la langue, allez l'apprendre. L'ignorance de la syntaxe du langage n'est pas une excuse. –

2

Je préfère la lisibilité sur l'intelligence (presque) à chaque fois, alors je vais certainement avec: if (Id == null || Id == 0)

2

serait encore mieux:

if(!Id.HasValue || Id == 0) 
    { 
    } 
+0

Non car 'Id.Value = 0', c'est-à-dire qu'il a une valeur et 0 – abatishchev

+0

Cela fonctionnerait si c'était: if (! Id.HasValue || Id == 0) {} – TurBas

+0

Je viens de réaliser le léger défaut - mis à jour –

4
if(Id.GetValueOrDefault() == 0) 

est également une option. En termes de performance, je doute qu'il y ait une réelle différence, et en tout cas vous feriez de la micro-optimisation, ce qui est rarement bénéfique.

2

Depuis c'est étiqueté « performance », voici mon conseil général sur des sujets tels que je pense toujours est valable ici:

  1. Mesure, mesure, mesure
  2. Ne pas micro-optimize à moins qu'il est la dernière chose que vous pouvez faire, et doivent encore obtenir quelques cycles sur une boucle de base

pour développer:

Il pourrait très bien être des choses présentes dans votre code cela rend ces conseils de micro-optimisation invalides ou non-optimaux, donc votre meilleure option concernant la performance est juste de la mesurer. Assurez-vous de mesurer suffisamment d'itérations d'une boucle en mesurant que le temps du petit code 1 va être perturbé par toutes les autres choses que votre machine invalide tout l'exercice.

En ce qui concerne les micro-optimisations, ne vous inquiétez pas. Choisissez celui que vous (et quiconque d'autre va maintenir le code) est le plus à l'aise avec, et se soucier des micro-optimisations si, et quand, vous avez réellement besoin de.

Personnellement, j'écris souvent le premier, c'est à dire.

if (o ?? 0 == 0) 

ou, dans le cas des cordes:

if ((s ?? string.Empty).Length == 0) 

Cependant, en termes de lisibilité et « ce qui semble le mieux », c'est un problème abri à vélo. Aller avec ce que vous voulez vous-même et se sentir à l'aise avec, et passer à de plus gros problèmes.

Modifier, Ok, j'ai arrêté de penser quelque part avant le dernier exemple de code.Je combiné deux choses différentes que je fais:

  1. Je laisse jamais les propriétés de chaîne et les champs comme null sauf si cela est utile
  2. Depuis 1. Je peux faire if (PropertyName.Length == 0)

Bien sûr, dans cet exemple particulier Je voudrais utiliser l'une des deux suivantes:

  1. if (string.IsNullOrEmpty(s))
  2. if (string.IsNullOrWhiteSpace(s)) (uniquement dans la version 4.0, et seulement si vous avez besoin)
+3

Je trouve '(s ?? string.Empty) .Length == 0' horrible quand vous avez' string.IsNullOrEmpty (s) '. –

+0

Ouais, je micro-optimisé: P –

+0

Cependant, considérons le cas général: '(s ??" ") .Length == x' .. Je trouve ça parfaitement bien - sauf pour avoir un null du tout, c'est ... –

1

Si vous utilisez ce code une seule fois, ce n'est pas tout à fait grande différence ce qu'il faut utiliser (mais, je préfère deuxième - il est plus facile à lire). Sinon, j'aimerais donner un nom de condition que je vérifie ici. Par exemple.

public class Foo 
{ 
    public int? Id { get; set; } 

    public bool IsNew 
    { 
    get 
    { 
     return (Id == null) || (Id == 0); 
    } 
    } 
} 

Maintenant, le code indique ce que vous vérifiez. Et il est lisible comme un livre

if (IsNew) {} 
+0

J'aime mieux mes livres quand ils ont des sujets dans leurs phrases. Lisible comme un livre serait: 'if (this.IsNew)'. (Juste en plaisantant, je ne vois rien de mal à omettre 'this' ici) –

+0

Eh bien, peut-être que c'est un Haiku :) –

-2

je vous recommande le second aussi le code doit de préférence comme suit

if (null == Id || 0 == Id) 
+0

Pouvez-vous expliquer pourquoi? Même si c'est pour des gains de performance, le gain serait sûrement minime et/ou équivalent à la ligne d'origine au moment où il serait optimisé. De plus, il se sent juste en arrière et IMO moins lisible. –

+0

elkdanger, c'est la pratique normale depuis les jours de VB. Pour le contrôle égal, nous spécifierons single = not two ==. Il y a donc plusieurs chances que la valeur du côté droit soit affectée à la valeur de gauche. Garder cette pratique dans mon esprit, je l'ai juste suggéré. Ce n'est pas un must. – Elangesh

+0

Egalement pratique courante en C/C++ où la condition d'une instruction if sera un entier et si mal typer '=' au lieu de '==' n'entraînera pas d'erreur de compilation. En plaçant la valeur constante sur la gauche, il y aura une erreur de compilation lors d'une erreur de frappe car le compilateur ne vous laissera pas affecter une variable à une constante (mais l'inverse est correct, d'où le problème.) ( –

1

Je pense que dans votre cas, le premier exemple pourrait être très légèrement plus rapide.

Je l'ai fait les deux façons LINQPad

void Main() 
{ 
    Foo f = new Foo(); 
    if ((Id ?? 0) == 0) {} // if (f.Id == null || f.Id == 0) {} 
} 

// Define other methods and classes here 
public class Foo 
{ 
    public int? Id { get; set; } 
} 

L'IL pour if ((Id ?? 0) == 0) {} est la suivante:

IL_0000: newobj  UserQuery+Foo..ctor 
IL_0005: stloc.0  
IL_0006: ldloc.0  
IL_0007: callvirt UserQuery+Foo.get_Id 
IL_000C: stloc.1  
IL_000D: ldloca.s 01 
IL_000F: call  System.Nullable<System.Int32>.get_HasValue 
IL_0014: brtrue.s IL_0019 
IL_0016: ldc.i4.0  
IL_0017: br.s  IL_0020 
IL_0019: ldloca.s 01 
IL_001B: call  System.Nullable<System.Int32>.GetValueOrDefault 

Foo.get_Id: 
IL_0000: ldarg.0  
IL_0001: ldfld  UserQuery+Foo.<Id>k__BackingField 
IL_0006: ret   

Foo.set_Id: 
IL_0000: ldarg.0  
IL_0001: ldarg.1  
IL_0002: stfld  UserQuery+Foo.<Id>k__BackingField 
IL_0007: ret   

Foo..ctor: 
IL_0000: ldarg.0  
IL_0001: call  System.Object..ctor 
IL_0006: ret  

IL pour if (f.Id == null || f.Id == 0) est inférieure à - note deux appels à get_HasValue

IL_0000: newobj  UserQuery+Foo..ctor 
IL_0005: stloc.0  
IL_0006: ldloc.0  
IL_0007: callvirt UserQuery+Foo.get_Id 
IL_000C: stloc.1  
IL_000D: ldloca.s 01 
IL_000F: call  System.Nullable<System.Int32>.get_HasValue 
IL_0014: brfalse.s IL_0031 
IL_0016: ldloc.0  
IL_0017: callvirt UserQuery+Foo.get_Id 
IL_001C: stloc.2  
IL_001D: ldloca.s 02 
IL_001F: call  System.Nullable<System.Int32>.GetValueOrDefault 
IL_0024: brtrue.s IL_002F 
IL_0026: ldloca.s 02 
IL_0028: call  System.Nullable<System.Int32>.get_HasValue 
IL_002D: br.s  IL_0030 
IL_002F: ldc.i4.0  

Foo.get_Id: 
IL_0000: ldarg.0  
IL_0001: ldfld  UserQuery+Foo.<Id>k__BackingField 
IL_0006: ret   

Foo.set_Id: 
IL_0000: ldarg.0  
IL_0001: ldarg.1  
IL_0002: stfld  UserQuery+Foo.<Id>k__BackingField 
IL_0007: ret   

Foo..ctor: 
IL_0000: ldarg.0  
IL_0001: call  System.Object..ctor 
IL_0006: ret   

Peut-être que je devrais en sortir plus!

+3

Pourquoi L'IL génère tout ce qui est pertinent à la question de la performance? ** L'IL ne fonctionne jamais. ** Ce qui est pertinent à la question de la performance est quel code génère la * gigue d'optimisation *, et la gigue va probablement inline l'appel à HasValue, puisqu'il ne s'agit que d'une seule lecture d'un champ booléen sur une structure –

+0

Merci pour l'info Eric Je suppose que je n'avais pas réalisé que l'optimisation réelle se produisait entre IL et le code machine plutôt qu'entre C# et IL, Je viens juste de voir ta réponse ici: http://stackoverflow.com/questions/2162541/is-the-c-compiler-smart-enough-to-optimize-this-code qui l'explique plus en détail. –

Questions connexes