Em VB.NET isso acontece:
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
Mas em C # isso acontece:
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");
}
Por que existe uma diferença?
default(decimal?)
está retornando 0, nãonull
.null
If
condicionais não precisam ser avaliados como booleanos ... uuuugh EDIT: Então, oNothing <> Anything = Nothing
que resulta na escolha daIf
rota negativa / else.Respostas:
VB.NET e C # .NET são linguagens diferentes, construídas por equipes diferentes que fizeram suposições diferentes sobre o uso; neste caso, a semântica de uma comparação NULL.
Minha preferência pessoal é pela semântica VB.NET, que em essência dá a NULL a semântica "Eu não sei ainda". Em seguida, a comparação de 5 com "Não sei ainda". é naturalmente "Não sei ainda"; ou seja, NULL. Isso tem a vantagem adicional de espelhar o comportamento de NULL na maioria dos bancos de dados SQL (se não em todos). Esta também é uma interpretação mais padrão (do que C #) da lógica de três valores, conforme explicado aqui .
A equipe C # fez diferentes suposições sobre o que NULL significa, resultando na diferença de comportamento que você mostra. Eric Lippert escreveu um blog sobre o significado de NULL em C # . Por Eric Lippert: "Eu também escrevi sobre a semântica de nulos em VB / VBScript e JScript aqui e aqui ".
Em qualquer ambiente no qual valores NULL são possíveis, é importante reconhecer que a Lei do Meio Excluído (isto é, que A ou ~ A é tautologicamente verdadeiro) não pode mais ser confiável.
Atualizar:
A
bool
(ao contrário de abool?
) só pode assumir os valores TRUE e FALSE. No entanto, uma implementação de linguagem de NULL deve decidir como NULL se propaga por meio de expressões. Em VB, as expressões5=null
e5<>null
AMBOS retornam falso. Em C #, das expressões comparáveis5==null
e5!=null
apenas asegundaprimeira [atualizado em 02/03/2014 - PG] retorna falso. Entretanto, em QUALQUER ambiente que suporte nulo, é responsabilidade do programador saber as tabelas de verdade e propagação de nulos usadas por aquela linguagem.Atualizar
Os artigos do blog de Eric Lippert (mencionados em seus comentários abaixo) sobre semântica estão agora em:
30 de setembro de 2003 - A Whole Lot of Nothing
1º de outubro de 2003 - Um pouco mais sobre nada
fonte
bool
não pode ter 3 valores, apenas dois. Ébool?
que pode ter três valores.operator ==
eoperator !=
ambos retornambool
, nãobool?
, independente do tipo dos operandos. Além disso, umaif
declaração só pode aceitar abool
, não abool?
.5=null
e5<>null
não são válidas. E de5 == null
e5 != null
, tem certeza de que é o segundo que voltafalse
?Porque
x <> y
retorna emNothing
vez detrue
. Simplesmente não está definido, poisx
não está definido. (semelhante a SQL null).Nota: VB.NET
Nothing
<> C #null
.Você também deve comparar o valor de a
Nullable(Of Decimal)
apenas se ele tiver um valor.Portanto, o VB.NET acima se compara a este (que parece menos incorreto):
A especificação da linguagem VB.NET :
Por exemplo:
fonte
Observe o CIL gerado (converti ambos para C #):
C #:
Visual básico:
Você verá que a comparação no Visual Basic retorna Nullable <bool> (não bool, false ou true!). E indefinido convertido em bool é falso.
Nothing
comparado a tudo o que é sempreNothing
, não falso no Visual Basic (é o mesmo que no SQL).fonte
O problema observado aqui é um caso especial de um problema mais geral, que é que o número de diferentes definições de igualdade que podem ser úteis em pelo menos algumas circunstâncias excede o número de meios comumente disponíveis para expressá-las. Em alguns casos, esse problema é agravado por uma crença infeliz de que é confuso ter diferentes meios de testar a igualdade produzindo resultados diferentes, e tal confusão pode ser evitada fazendo com que as diferentes formas de igualdade produzam os mesmos resultados sempre que possível.
Na realidade, a causa fundamental da confusão é uma crença equivocada de que se deve esperar que as diferentes formas de teste de igualdade e desigualdade produzam o mesmo resultado, não obstante o fato de que semânticas diferentes são úteis em circunstâncias diferentes. Por exemplo, do ponto de vista aritmético, é útil ser capaz de ter
Decimal
quais diferem apenas no número de zeros à direita comparados como iguais. Da mesma forma paradouble
valores como zero positivo e zero negativo. Por outro lado, do ponto de vista de cache ou internamento, essa semântica pode ser mortal. Suponha, por exemplo, que alguém tenha umDictionary<Decimal, String>
tal quemyDict[someDecimal]
deve ser igualsomeDecimal.ToString()
. Tal objeto pareceria razoável se alguém tivesse muitosDecimal
valores que se deseja converter em string e espera-se que haja muitas duplicatas. Infelizmente, se usado esse cache para converter 12,3 me 12,40 m, seguidos por 12,30 me 12,4 m, os últimos valores renderiam "12,3" e "12,40" em vez de "12,30" e "12,4".Voltando ao assunto em questão, há mais de uma maneira sensata de comparar objetos anuláveis para igualdade. C # assume o ponto de vista de que seu
==
operador deve espelhar o comportamento deEquals
. O VB.NET considera que seu comportamento deve espelhar o de algumas outras linguagens, já que quem quiser oEquals
comportamento pode usarEquals
. Em certo sentido, a solução certa seria ter uma construção "se" de três vias e exigir que, se a expressão condicional retornar um resultado com três valores, o código deve especificar o que deve acontecer nonull
caso. Já que essa não é uma opção com as línguas como elas são, a próxima melhor alternativa é simplesmente aprender como diferentes línguas funcionam e reconhecer que não são iguais.A propósito, o operador "Is" do Visual Basic, que está faltando em C, pode ser usado para testar se um objeto anulável é, de fato, nulo. Embora alguém possa questionar se um
if
teste deve aceitar umBoolean?
, fazer com que os operadores de comparação normais retornem emBoolean?
vez deBoolean
quando invocados em tipos anuláveis é um recurso útil. A propósito, no VB.NET, se alguém tentar usar o operador de igualdade em vez deIs
, obterá um aviso de que o resultado da comparação sempre seráNothing
, e deve-Is
se usar se quiser testar se algo é nulo.fonte
== null
. E testar se um tipo de valor anulável tem um valor é feito por.hasValue
. Qual a utilidade de umIs Nothing
operador? C # tem,is
mas testa a compatibilidade de tipo. À luz disso, realmente não tenho certeza do que seu último parágrafo está tentando dizer.null
, embora ambas as linguagens tratem isso como um açúcar sintático para umaHasValue
verificação, pelo menos nos casos em que o tipo é conhecido (não tenho certeza qual código é gerado para genéricos).Pode ser que este post te ajude:
Se bem me lembro, 'Nada' em VB significa "o valor padrão". Para um tipo de valor, esse é o valor padrão, para um tipo de referência, que seria nulo. Portanto, não atribuir nada a uma estrutura não é problema algum.
fonte
<>
operador em VB e como ele opera em tipos anuláveis.Esta é uma estranheza definitiva do VB.
No VB, se você deseja comparar dois tipos anuláveis, você deve usar
Nullable.Equals()
.Em seu exemplo, deveria ser:
fonte
Nullable<>.Equals()
. Pode-se esperar que funcione da mesma maneira (que é o que C # faz).Nullable
não existia nas primeiras versões do .NET, ela foi criada depois que o C # e o VB.NET já estavam fora de uso há algum tempo e já determinavam seu comportamento de propagação nula. Você honestamente espera que a linguagem seja consistente com um tipo que não será criado por muitos anos? Do ponto de vista de um programador VB.NET, é Nullable.Equals que não é consistente com a linguagem, ao invés do contrário. (Dado que C # e VB usam a mesmaNullable
definição, não havia como ser consistente com as duas linguagens.)Seu código VB está simplesmente incorreto - se você alterar "x <> y" para "x = y", ainda terá "false" como resultado. A forma mais comum de expressão para instâncias anuláveis é "Not x.Equals (y)", e isso produzirá o mesmo comportamento de "x! = Y" em C #.
fonte
x
sejanothing
, nesse casox.Equals(y)
lançará uma exceção.