530 votes

Quelle est la différence entre Nullable<T>.HasValue et Nullable<T> != null ?

J'ai toujours utilisé Nullable<>.HasValue parce que j'aimais la sémantique. Cependant, j'ai récemment travaillé sur la base de code existante de quelqu'un d'autre qui utilisait Nullable<> != null exclusivement.

Y a-t-il une raison d'utiliser l'un plutôt que l'autre, ou s'agit-il d'une simple préférence ?

  1. int? a; if (a.HasValue) // ...

vs.

  1. int? b; if (b != null) // ...

10 votes

J'ai posé une question similaire... j'ai obtenu de bonnes réponses : stackoverflow.com/questions/633286/

3 votes

Personnellement J'utiliserais HasValue car je pense que les mots ont tendance à être plus lisibles que les symboles. Mais tout dépend de vous et de ce qui correspond à votre style.

1 votes

.HasValue est plus logique car il indique que le type est de type T? plutôt qu'un type qui peut être nullable comme les chaînes de caractères.

583voto

Rex M Points 80372

Le compilateur remplace null avec un appel à HasValue Il n'y a donc pas de réelle différence. Il suffit de choisir ce qui est le plus lisible ou le plus logique pour vous et vos collègues.

92 votes

J'ajouterais à cela "celui qui est le plus cohérent/qui suit un style de codage existant".

22 votes

La vie est belle. Je déteste ce sucre syntactique. int? x = null me donne l'illusion qu'une instance nullable est un type de référence. Mais la vérité est que Nullable<T> est un type valeur. J'ai l'impression que j'obtiendrais une NullReferenceException : int? x = null; Use(x.HasValue) .

15 votes

@KFL Si le sucre syntaxique vous gêne, utilisez simplement Nullable<int> au lieu de int? .

60voto

cbp Points 9676

Je préfère (a != null) afin que la syntaxe corresponde aux types de référence.

16 votes

Ce qui est bien sûr trompeur, puisque Nullable<> es no un type de référence.

12 votes

Oui, mais le fait n'a généralement que très peu d'importance au moment où l'on procède à une vérification nulle.

50 votes

Elle n'est trompeuse que pour les personnes confuses sur le plan conceptuel. L'utilisation d'une syntaxe cohérente pour deux types différents n'implique pas qu'il s'agit du même type. C# a des types de référence nullables (tous les types de référence sont actuellement nullables, mais cela changera à l'avenir) et des types de valeur nullables. Il est logique d'utiliser une syntaxe cohérente pour tous les types nullables. Cela n'implique en aucun cas que les types de valeur nullables sont des types de référence, ou que les types de référence nullables sont des types de valeur.

23voto

Perrin Larson Points 11

J'ai fait quelques recherches à ce sujet en utilisant différentes méthodes pour assigner des valeurs à un int nullable. Voici ce qui s'est passé lorsque j'ai fait différentes choses. Cela devrait clarifier ce qui se passe. N'oubliez pas : Nullable<something> ou l'abréviation something? est une structure pour laquelle le compilateur semble faire beaucoup de travail pour nous permettre de l'utiliser avec null comme s'il s'agissait d'une classe.
Comme vous le verrez ci-dessous, SomeNullable == null y SomeNullable.HasValue renverra toujours un vrai ou un faux. Bien que cela ne soit pas démontré ci-dessous, SomeNullable == 3 est également valide (en supposant que SomeNullable est un int? ).
Tandis que SomeNullable.Value Nous obtenons une erreur d'exécution si nous avons assigné null a SomeNullable . C'est en fait le seul cas où les nullables pourraient nous poser problème, grâce à une combinaison d'opérateurs surchargés, de object.Equals(obj) et l'optimisation du compilateur et les affaires de singe.

Voici une description d'un code que j'ai exécuté et des résultats qu'il a produits sous forme d'é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 méthode d'initialisation suivante :

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 auparavant. Gardez à l'esprit que l'initialisation avec int? val = new int?(null); avec null passé au constructeur, aurait produit une erreur de temps de COMPILATION, puisque la VALEUR de l'objet nullable n'est PAS nullable. Ce n'est que l'objet enveloppant lui-même qui peut être égal à null.

De même, nous obtiendrions une erreur au moment de la compilation à partir 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 là encore, les opérateurs de conversion implicites surchargés polymorphes nous permettent de le faire :

val = 3;

Il n'y a pas lieu de s'inquiéter des polysomnies, du moment qu'elles fonctionnent bien :)

9 votes

"Gardez à l'esprit que Nullable<quelque chose> ou l'abréviation quelque chose ? est une classe." C'est faux ! Nullable<T> est une structure. Elle surcharge les opérateurs Equals et == pour qu'ils renvoient true lorsqu'ils sont comparés à null. Le compilateur ne fait pas de travail sophistiqué pour cette comparaison.

1 votes

@andrewjs - Vous avez raison de dire qu'il s'agit d'une structure (et non d'une classe), mais vous avez tort de dire qu'elle surcharge l'opérateur ==. Si vous tapez Nullable<X> dans VisualStudio 2013 et F12, vous verrez qu'il ne surcharge que la conversion vers et à partir de X et le Equals(object other) méthode. Cependant, je pense que l'opérateur == utilise cette méthode par défaut, de sorte que l'effet est le même. En fait, cela fait un moment que j'ai l'intention de mettre à jour cette réponse sur ce fait, mais je suis paresseux et/ou occupé. Ce commentaire devra faire l'affaire pour l'instant :)

0 votes

J'ai fait une vérification rapide avec ildasm et vous avez raison sur le fait que le compilateur fait de la magie ; comparer un objet Nullable<T> à null se traduit en effet par un appel à HasValue. Intéressant !

15voto

Carter Points 3877

En VB.Net. N'utilisez PAS "IsNot Nothing" lorsque vous pouvez utiliser ".HasValue". Je viens de résoudre une erreur "Operation could destabilize the runtime" Medium trust en remplaçant "IsNot Nothing" par ".HasValue" à un endroit. 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.

12 votes

Je préférerais HasValue pour des raisons de lisibilité. IsNot Nothing est une expression vraiment laide (à cause de la double négation).

12 votes

@steffan "IsNot Nothing" n'est pas une double négation. "Rien" n'est pas une négation, c'est une quantité discrète, même en dehors du domaine de la programmation. "Cette quantité n'est pas rien" est, grammaticalement, exactement la même chose que de dire "Cette quantité n'est pas zéro" et ce n'est pas non plus une double négation.

8 votes

Ce n'est pas que je ne veuille pas être d'accord avec l'absence de vérité ici, mais voyons. IsNot Nothing est clairement, eh bien, trop négatif. Pourquoi ne pas écrire quelque chose de positif et de clair comme HasValue ? Ce n'est pas un test de grammaire, c'est du codage, où l'objectif principal est la clarté.

0voto

yan yankelevich Points 600

Si vous utilisez linq et que vous voulez garder votre code court, je recommande de toujours utiliser !=null

Et voici 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 les Foo avec une valeur SomeDouble non nulle à partir d'une collection de Foo (en supposant que certains Foo de la collection peuvent également être nuls), nous nous retrouvons avec au moins trois façons d'écrire notre fonction (si nous utilisons 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
}

Dans ce genre de situation, je recommande de toujours choisir le plus court.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X