J'ai toujours utilisé Nullable<>.HasValue
parce que j'aimais la sémantique. Cependant, récemment, je travaillais sur la base de code de quelqu'un d'autre où ils utilisaient exclusivement Nullable<> != null
.
Y a-t-il une raison pour utiliser l'un sur l'autre, ou est-ce purement la préférence?
int? a;
if (a.HasValue)
// ...
vs.
int? b;
if (b != null)
// ...
Le compilateur remplace les comparaisons nulles par un appel à HasValue
, de sorte qu'il n'y a pas de réelle différence. Faites simplement ce qui est le plus lisible/a plus de sens pour vous et vos collègues.
Je préfère (a != null)
pour que la syntaxe corresponde aux types de référence.
J'ai effectué des recherches à ce sujet en utilisant différentes méthodes pour attribuer des valeurs à un int nullable. Voici ce qui s'est passé quand j'ai fait diverses choses. Devrait clarifier ce qui se passe. Gardez à l'esprit: Nullable<something>
ou le raccourci something?
est une structure pour laquelle le compilateur semble faire beaucoup de travail pour nous permettre d'utiliser null comme s'il s'agissait d'une classe.
Comme vous le verrez ci-dessous, SomeNullable == null
et SomeNullable.HasValue
renverront toujours une valeur true ou false attendue. Bien que cela ne soit pas démontré ci-dessous, SomeNullable == 3
est également valide (en supposant que SomeNullable est un int?
).
While SomeNullable.Value
nous génère une erreur d’exécution si nous assignions null
à SomeNullable
. C'est en fait le seul cas où nullables pourrait nous causer un problème, grâce à une combinaison d'opérateurs surchargés, de méthode surchargée object.Equals(obj)
et d'optimisation du compilateur et de l'activité de singe.
Voici une description du code que j'ai exécuté et des résultats obtenus dans les étiquettes:
int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Ok, essayons la prochaine méthode d'initialisation:
int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Tout comme avant. N'oubliez pas que l'initialisation avec int? val = new int?(null);
, avec la valeur null transmise au constructeur, aurait généré une erreur de temps COMPILE, car la valeur VALUE de l'objet nullable n'est PAS nullable. Seul l'objet wrapper lui-même peut être égal à null.
De même, nous aurions une erreur de compilation lors de:
int? val = new int?();
val.Value = null;
sans oublier que val.Value
est de toute façon une propriété en lecture seule, ce qui signifie que nous ne pouvons même pas utiliser quelque chose comme:
val.Value = 3;
mais encore une fois, les opérateurs de conversion implicite polymorphe surchargés nous permettent de faire:
val = 3;
Pas besoin de s'inquiéter de la polysomnie, mais tant qu'elle fonctionne correctement? :)
En VB.Net. N'utilisez PAS "IsNot Nothing" lorsque vous pouvez utiliser ".HasValue". Je viens de résoudre une erreur "Une opération peut déstabiliser le moteur d'exécution". Erreur de confiance moyenne en remplaçant "IsNot Nothing" par ".HasValue". Je ne comprends pas vraiment pourquoi, mais quelque chose se passe différemment dans le compilateur. Je suppose que "! = Null" en C # peut avoir le même problème.
Si vous utilisez linq et que votre code est court, je vous recommande de toujours utiliser !=null
Et c'est pourquoi:
Imaginons que nous ayons une classe Foo
avec un nullable double variable SomeDouble
public class Foo
{
public double? SomeDouble;
//some other properties
}
Si quelque part dans notre code nous voulons obtenir tous Foo avec des valeurs SomeDouble non nulles d'une collection de Foo (en supposant que certains foos de la collection peuvent être nuls aussi), nous avons au moins trois façons d'écrire notre fonction (si utiliser C # 6):
public IEnumerable<Foo> GetNonNullFoosWithSomeDoubleValues(IEnumerable<Foo> foos)
{
return foos.Where(foo => foo?.SomeDouble != null);
return foos.Where(foo=>foo?.SomeDouble.HasValue); // compile time error
return foos.Where(foo=>foo?.SomeDouble.HasValue == true);
return foos.Where(foo=>foo != null && foo.SomeDouble.HasValue); //if we don't use C#6
}
Et dans ce genre de situation, je recommande de toujours choisir le plus court.