Dans VB.NET, cela se produit:
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false") '' <-- I got this. Why?
End If
Mais en C #, cela se produit:
decimal? x = default(decimal?);
decimal? y = default(decimal?);
y = 5;
if (x != y)
{
Debug.WriteLine("true"); // <-- I got this -- I'm with you, C# :)
}
else
{
Debug.WriteLine("false");
}
Pourquoi y a-t-il une différence?
default(decimal?)
renvoie 0, nonnull
.null
If
conditions ne nécessitent pas d'être évaluées comme un booléen ... uuuugh EDIT: Donc,Nothing <> Anything = Nothing
ce qui entraîne laIf
prise de la route négative / autre.Réponses:
VB.NET et C # .NET sont des langages différents, construits par différentes équipes qui ont fait des hypothèses différentes sur l'utilisation; dans ce cas, la sémantique d'une comparaison NULL.
Ma préférence personnelle est pour la sémantique VB.NET, qui donne essentiellement à NULL la sémantique «je ne sais pas encore». Puis la comparaison de 5 à "Je ne sais pas encore". est naturellement "je ne sais pas encore"; c'est-à-dire NULL. Cela présente l'avantage supplémentaire de refléter le comportement de NULL dans (la plupart sinon la totalité) des bases de données SQL. C'est aussi une interprétation plus standard (que celle de C #) de la logique à trois valeurs, comme expliqué ici .
L'équipe C # a fait différentes hypothèses sur la signification de NULL, ce qui a entraîné la différence de comportement que vous montrez. Eric Lippert a écrit un blog sur la signification de NULL en C # . Per Eric Lippert: "J'ai aussi écrit sur la sémantique des nulls en VB / VBScript et JScript ici et ici ".
Dans tout environnement dans lequel des valeurs NULL sont possibles, il est important de reconnaître que la loi du milieu exclu (c'est-à-dire que A ou ~ A est tautologiquement vrai) ne peut plus être invoquée.
Mettre à jour:
A
bool
(par opposition à abool?
) ne peut prendre que les valeurs TRUE et FALSE. Cependant, une implémentation de langage de NULL doit décider de la façon dont NULL se propage à travers les expressions. Dans VB, les expressions5=null
et5<>null
LES DEUX renvoient false. En C #, des expressions comparables5==null
et5!=null
seule ladeuxièmepremière [mise à jour 2014-03-02 - PG] renvoie false. Cependant, dans N'IMPORTE QUEL environnement qui prend en charge NULL, il incombe au programmeur de connaître les tables de vérité et la propagation Null utilisées par ce langage.Mettre à jour
Les articles du blog d'Eric Lippert (mentionnés dans ses commentaires ci-dessous) sur la sémantique sont maintenant à:
30 septembre 2003 - Beaucoup de rien
1 octobre 2003 - Un peu plus sur rien
la source
bool
ne peut pas avoir 3 valeurs, seulement deux. C'estbool?
ça qui peut avoir trois valeurs.operator ==
et lesoperator !=
deux renvoientbool
, nonbool?
, quel que soit le type des opérandes. De plus, uneif
instruction ne peut accepter qu'unbool
, pas unbool?
.5=null
et5<>null
ne sont pas valides. Et de5 == null
et5 != null
, êtes-vous sûr que c'est le second qui revientfalse
?Parce que
x <> y
revientNothing
au lieu detrue
. Il n'est tout simplement pas défini car ilx
n'est pas défini. (similaire à SQL null).Remarque: VB.NET
Nothing
<> C #null
.Vous devez également comparer la valeur de a
Nullable(Of Decimal)
uniquement si elle a une valeur.Ainsi, le VB.NET ci-dessus se compare à ceci (qui semble moins incorrect):
La spécification du langage VB.NET :
Par exemple:
la source
Regardez le CIL généré (j'ai converti les deux en C #):
C #:
Visual Basic:
Vous verrez que la comparaison dans Visual Basic renvoie Nullable <bool> (pas booléen, false ou true!). Et undefined converti en booléen est faux.
Nothing
par rapport à ce qui est toujoursNothing
, pas faux dans Visual Basic (c'est le même que dans SQL).la source
Le problème observé ici est un cas particulier d'un problème plus général, à savoir que le nombre de définitions différentes de l'égalité qui peuvent être utiles dans au moins certaines circonstances dépasse le nombre de moyens couramment disponibles pour les exprimer. Ce problème est dans certains cas aggravé par une malheureuse croyance qu'il est déroutant d'avoir différents moyens de tester l'égalité donnant des résultats différents, et une telle confusion pourrait être évitée en faisant en sorte que les différentes formes d'égalité donnent les mêmes résultats chaque fois que possible.
En réalité, la cause fondamentale de la confusion est une croyance erronée selon laquelle les différentes formes de tests d'égalité et d'inégalité devraient produire le même résultat, même si des sémantiques différentes sont utiles dans des circonstances différentes. Par exemple, d'un point de vue arithmétique, il est utile de pouvoir
Decimal
comparer les valeurs qui ne diffèrent que par le nombre de zéros à la fin. De même pour desdouble
valeurs telles que zéro positif et zéro négatif. D'un autre côté, du point de vue de la mise en cache ou de l'internement, une telle sémantique peut être mortelle. Supposons, par exemple, que l'on ait unDictionary<Decimal, String>
tel quimyDict[someDecimal]
devrait égalersomeDecimal.ToString()
. Un tel objet semblerait raisonnable si l'on avait plusieursDecimal
valeurs que l'on voulait convertir en chaîne et s'attendait à ce qu'il y ait de nombreux doublons. Malheureusement, si une telle mise en cache était utilisée pour convertir 12,3 m et 12,40 m, suivis de 12,30 m et 12,4 m, ces dernières valeurs donneraient «12,3» et «12,40» au lieu de «12,30» et «12,4».Pour en revenir à la question à l'étude, il existe plus d'une manière sensée de comparer des objets Nullable pour l'égalité. C # part du principe que son
==
opérateur doit refléter le comportement deEquals
. VB.NET part du principe que son comportement doit refléter celui de certains autres langages, car quiconque souhaite leEquals
comportement peut l'utiliserEquals
. Dans un certain sens, la bonne solution serait d'avoir une construction "si" à trois voies et d'exiger que si l'expression conditionnelle renvoie un résultat à trois valeurs, le code doit spécifier ce qui doit se passer dans lenull
cas. Étant donné que ce n'est pas une option avec les langues telles qu'elles sont, la meilleure alternative consiste simplement à apprendre comment les différentes langues fonctionnent et à reconnaître qu'elles ne sont pas les mêmes.Incidemment, l'opérateur "Est" de Visual Basic, qui fait défaut dans C, peut être utilisé pour tester si un objet Nullable est, en fait, null. Bien que l'on puisse raisonnablement se demander si un
if
test devrait accepter aBoolean?
, avoir les opérateurs de comparaison normaux retournentBoolean?
plutôt queBoolean
lorsqu'ils sont appelés sur des types Nullable est une fonctionnalité utile. Incidemment, dans VB.NET, si l'on tente d'utiliser l'opérateur d'égalité plutôt queIs
, on obtiendra un avertissement que le résultat de la comparaison sera toujoursNothing
, et on devrait l'utiliserIs
si l'on veut tester si quelque chose est nul.la source
== null
. Et tester si un type de valeur Nullable a une valeur est effectué par.hasValue
. À quoi sert unIs Nothing
opérateur? C # a,is
mais il teste la compatibilité des types. À la lumière de ces éléments, je ne sais vraiment pas ce que votre dernier paragraphe essaie de dire.null
, bien que les deux langues traitent cela comme du sucre syntaxique pour uneHasValue
vérification, au moins dans les cas où le type est connu (je ne suis pas sûr quel code est généré pour les génériques).Peut-être que cet article vous aidera:
Si je me souviens bien, «Rien» dans VB signifie «la valeur par défaut». Pour un type valeur, c'est la valeur par défaut, pour un type référence, ce serait null. Ainsi, n'attribuer rien à une structure ne pose aucun problème.
la source
<>
opérateur dans VB, et comment il fonctionne sur les types Nullable.C'est une étrange bizarrerie de VB.
Dans VB, si vous souhaitez comparer deux types Nullable, vous devez utiliser
Nullable.Equals()
.Dans votre exemple, cela devrait être:
la source
Nullable<>.Equals()
. On pourrait s'attendre à ce que cela fonctionne de la même manière (ce que fait C #).Nullable
n'existait pas dans les premières versions de .NET, elle a été créée après que C # et VB.NET soient sortis depuis un certain temps et ont déjà déterminé leur comportement de propagation nul. Pensez-vous honnêtement que le langage soit cohérent avec un type qui n'aura pas été créé avant plusieurs années? Du point de vue d'un programmeur VB.NET, c'est Nullable.Equals qui n'est pas cohérent avec le langage, plutôt que l'inverse. (Étant donné que C # et VB utilisent tous les deux la mêmeNullable
définition, il n'y avait aucun moyen pour que cela soit cohérent avec les deux langues.)Votre code VB est tout simplement incorrect - si vous changez le "x <> y" en "x = y", vous aurez toujours "faux" comme résultat. La manière la plus courante d'exprimer ceci pour les instances Nullable est "Not x.Equals (y)", et cela donnera le même comportement que "x! = Y" en C #.
la source
x
soitnothing
, auquel casx.Equals(y)
lancera une exception.