J'ai toujours utilisé Nullable<>.HasValue
parce que j'aimais la sémantique. Cependant, récemment, je travaillais sur la base de code existante de quelqu'un d'autre où ils l'utilisaient Nullable<> != null
exclusivement à la place.
Y a-t-il une raison de les utiliser l'un par rapport à l'autre, ou s'agit-il uniquement de préférence?
int? a; if (a.HasValue) // ...
contre.
int? b; if (b != null) // ...
HasValue
car je pense que les mots ont tendance à être plus lisibles que les symboles. Tout dépend de vous, et de ce qui correspond à votre style actuel..HasValue
est plus logique car il indique que le type est de typeT?
plutôt qu'un type qui peut être annulable tel que des chaînes.Réponses:
Le compilateur remplace les comparaisons nulles par un appel à
HasValue
, il n'y a donc pas de réelle différence. Faites simplement ce qui est plus lisible / plus logique pour vous et vos collègues.la source
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 de valeur. Il se sent j'obtenir un NullReferenceException faire:int? x = null; Use(x.HasValue)
.Nullable<int>
place deint?
.Je préfère
(a != null)
que la syntaxe corresponde aux types de référence.la source
Nullable<>
n'est pas un type de référence.HasValue
parce que c'est plus lisible que!= null
J'ai fait quelques recherches à ce sujet en utilisant différentes méthodes pour attribuer des valeurs à un entier nullable. Voici ce qui s'est passé lorsque j'ai fait diverses choses. Devrait clarifier ce qui se passe. Gardez à l'esprit:
Nullable<something>
ou le raccourcisomething?
est une structure pour laquelle le compilateur semble faire beaucoup de travail pour nous permettre d'utiliser avec null comme s'il s'agissait d'une classe.Comme vous le verrez ci-dessous,
SomeNullable == null
etSomeNullable.HasValue
retournera toujours un vrai ou un faux attendu. Bien que cela ne soit pas démontré ci-dessous, ilSomeNullable == 3
est également valide (en supposant que SomeNullable est unint?
).Alors que
SomeNullable.Value
nous obtient une erreur d'exécution si nous avons attribuénull
àSomeNullable
. C'est en fait le seul cas où nullables pourrait nous poser problème, grâce à une combinaison d'opérateurs surchargés, surchargésobject.Equals(obj)
méthode, et optimisation du compilateur et entreprise de singe.Voici une description du code que j'ai exécuté et de la sortie qu'il a produite dans les étiquettes:
Ok, essayons la prochaine méthode d'initialisation:
Tout comme avant. 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, car la valeur de l'objet nullable n'est PAS nullable. Seul l'objet wrapper lui-même peut être égal à null.De même, nous obtiendrions une erreur de temps de compilation de:
sans compter que
val.Value
c'est une propriété en lecture seule de toute façon, ce qui signifie que nous ne pouvons même pas utiliser quelque chose comme:mais encore une fois, les opérateurs de conversion implicites surchargés polymorphes nous permettent de faire:
Pas besoin de s'inquiéter de tout ce qui peut arriver, tant qu'il fonctionne bien? :)
la source
Nullable<X>
VisualStudio 2013 et F12, vous verrez qu'il surcharge uniquement la conversion vers et depuisX
et laEquals(object other)
méthode. Cependant, je pense que l'opérateur == utilise cette méthode par défaut, donc l'effet est le même. En fait, je voulais mettre à jour cette réponse sur ce fait depuis un certain temps maintenant, mais je suis paresseux et / ou occupé. Ce commentaire devra faire pour l'instant :)int? val = 42; val.GetType() == typeof(int)
). Donc, non seulement est une structure nullable qui peut être égale à null, mais ce n'est souvent pas du tout une nullable! : D De la même manière, lorsque vous encadrez une valeur annulable, vous boxezint
, nonint?
- et lorsque leint?
n'a pas de valeur, vous obtenez à lanull
place d'une valeur annulable encadrée. Cela signifie essentiellement qu'il y a rarement des frais généraux pour utiliser correctementNull
un type en .NET? Pouvez-vous indiquer la partie de la spécification CLR / C # où cela est dit? Les nullables sont bien définis dans la spécification CLR, leur comportement n'est pas une "implémentation d'une abstraction" - c'est un contrat . Mais si le mieux que vous puissiez faire est des attaques ad hominem, amusez-vous.Dans VB.Net. N'utilisez PAS "IsNot Nothing" lorsque vous pouvez utiliser ".HasValue". Je viens de résoudre une "Opération pourrait déstabiliser le runtime" Erreur de confiance moyenne 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.
la source
HasValue
raison de la lisibilité.IsNot Nothing
est vraiment une expression laide (à cause de la double négation).Si vous utilisez linq et souhaitez garder votre code court, je recommande de toujours utiliser
!=null
Et c'est pourquoi:
Imaginons que nous ayons une classe
Foo
avec une variable double nullableSomeDouble
Si, quelque part dans notre code, nous voulons obtenir tous les Foo avec des valeurs SomeDouble non nulles d'une collection de Foo (en supposant que certains foos de la collection peuvent également être nuls), nous nous retrouvons avec au moins trois façons d'écrire notre fonction (si nous utilisez C # 6):
Et dans ce genre de situation, je recommande de toujours opter pour la plus courte
la source
foo?.SomeDouble.HasValue
est une erreur de compilation (pas un "lancer" dans ma terminologie) dans ce contexte parce que son type n'estbool?
pas justebool
. (La.Where
méthode veut unFunc<Foo, bool>
.) Il est permis de le faire(foo?.SomeDouble).HasValue
, bien sûr, car cela a du typebool
. C'est ce que votre première ligne est "traduite" en interne par le compilateur C # (au moins formellement).Réponse générale et règle générale: si vous avez une option (par exemple, écrire des sérialiseurs personnalisés) pour traiter Nullable dans un pipeline différent de
object
- et utiliser leurs propriétés spécifiques - faites-le et utilisez des propriétés spécifiques Nullable. Donc, d'un point de vue cohérentHasValue
devrait être préféré. Une réflexion cohérente peut vous aider à écrire un meilleur code sans passer trop de temps dans les détails. Par exemple, la deuxième méthode sera beaucoup plus efficace (principalement à cause des compilateurs en ligne et en boxe, mais les chiffres sont toujours très expressifs):Test de référence:
Code de référence:
https://github.com/dotnet/BenchmarkDotNet a été utilisé
PS . Les gens disent que les conseils "préfèrent HasValue en raison d'une pensée cohérente" ne sont pas liés et inutiles. Pouvez-vous prédire les performances de cela?
PPS Les gens continuent moins, mais personne n'essaie de prédire les performances de
CheckNullableGenericImpl
. Et le compilateur ne vous aidera pas à le remplacer!=null
parHasValue
.HasValue
doit être utilisé directement si vous êtes intéressé par les performances.la source
CheckObjectImpl
boîtes peuvent être annulées dans unobject
, alors qu'ellesCheckNullableImpl
n'utilisent pas de boxe. La comparaison est donc très injuste. Non seulement il est parce que non prix, il est également inutile, comme il est indiqué dans la réponse acceptée , le compilateur réécritures!=
àHasValue
toute façon.Nullable<T>
, vous le faites (en le mettant dans unobject
). Lorsque vous appliquez!= null
avec un nullable sur la gauche, aucune boxe ne se produit car la prise en charge!=
de nullables fonctionne au niveau du compilateur. C'est différent lorsque vous masquez le nullable du compilateur en le plaçant d'abord dans unobject
. NiCheckObjectImpl(object o)
votre point de repère n'ont de sens en principe.CheckObjectImpl
son corps à l' intérieurCheckObject
. Cependant, vos derniers commentaires révèlent que vous aviez en fait une question complètement différente à l'esprit lorsque vous avez décidé de répondre à cette question vieille de 8 ans, ce qui rend votre réponse trompeuse dans le contexte de la question d'origine. Ce n'était pas ce que le PO demandait.what is faster != or HasValue
. Il arrive à cette question, parcourt votre réponse, apprécie votre point de repère et dit: "Gee, je ne l'utiliserai jamais!=
parce que c'est clairement tellement plus lent!" C'est une très mauvaise conclusion qu'il poursuivra ensuite en se répandant. C'est pourquoi je crois que votre réponse est nuisible - elle répond à une mauvaise question et pose donc une mauvaise conclusion au lecteur sans méfiance. Réfléchissez à ce qui se passe lorsque vous changez votre statutCheckNullableImpl
pour être égalementreturn o != null;
.!=
etHasValue
alors qu'en fait elle montre la différence entreobject o
etT? o
. Si vous faites ce que j'ai suggéré, c'est-à-dire, réécrivezCheckNullableImpl
commepublic static bool CheckNullableImpl<T>(T? o) where T: struct { return o != null; }
, vous vous retrouverez avec une référence qui montre clairement que!=
c'est beaucoup plus lent que!=
. Ce qui devrait vous conduire à la conclusion que la question de votre réponse décrit est pas!=
contreHasValue
du tout.