Eu sempre usei Nullable<>.HasValue
porque gostei da semântica. No entanto, recentemente eu estava trabalhando na base de código existente de outra pessoa, onde ela usava Nullable<> != null
exclusivamente.
Existe uma razão para usar um sobre o outro, ou é pura preferência?
int? a; if (a.HasValue) // ...
vs.
int? b; if (b != null) // ...
HasValue
uma vez que acho que as palavras tendem a ser mais legíveis que os símbolos. Tudo depende de você, e o que se encaixa no seu estilo existente..HasValue
faz mais sentido, pois indica que o tipo é do tipo, emT?
vez de um tipo que pode ser anulável, como seqüências de caracteres.Respostas:
O compilador substitui comparações nulas por uma chamada para
HasValue
, portanto, não há diferença real. Faça o que for mais legível / faça mais sentido para você e seus colegas.fonte
int? x = null
me dá a ilusão de que uma instância anulável é um tipo de referência. Mas a verdade é que Nullable <T> é um tipo de valor. Parece que eu obter um NullReferenceException fazer:int? x = null; Use(x.HasValue)
.Nullable<int>
vez deint?
.Eu prefiro
(a != null)
que a sintaxe corresponda aos tipos de referência.fonte
Nullable<>
é um tipo de referência.HasValue
porque é mais legível do que o #!= null
Eu fiz algumas pesquisas sobre isso usando métodos diferentes para atribuir valores a um int nulo. Aqui está o que aconteceu quando eu fiz várias coisas. Deve esclarecer o que está acontecendo. Lembre-se:
Nullable<something>
ou a abreviaçãosomething?
é uma estrutura para a qual o compilador parece estar fazendo muito trabalho para nos deixar usar com nulo como se fosse uma classe.Como você verá abaixo,
SomeNullable == null
eSomeNullable.HasValue
sempre retornará um esperado verdadeiro ou falso. Embora não demonstrado abaixo, tambémSomeNullable == 3
é válido (assumindo que SomeNullable é umint?
).Enquanto
SomeNullable.Value
isso, obtemos um erro de tempo de execução se atribuímosnull
ao método, otimização do compilador e negócios de macaco.SomeNullable
. Este é, de fato, o único caso em que anuláveis podem nos causar um problema, graças a uma combinação de operadores sobrecarregados, sobrecarregados.object.Equals(obj)
Aqui está uma descrição de algum código que eu executei e qual saída ele produziu nos rótulos:
Ok, vamos tentar o próximo método de inicialização:
Tudo o mesmo de antes. Lembre-se de que a inicialização com
int? val = new int?(null);
, com nulo passado para o construtor, teria produzido um erro de tempo COMPILE, pois VALUE do objeto anulável NÃO é anulável. É apenas o próprio objeto wrapper que pode ser igual a nulo.Da mesma forma, receberíamos um erro de tempo de compilação em:
para não mencionar que
val.Value
é uma propriedade somente leitura de qualquer maneira, o que significa que não podemos nem usar algo como:mas, novamente, operadores de conversão implícita sobrecarregados polimórficos nos permitem:
Não há necessidade de se preocupar com o que você chama de polissom, desde que funcione corretamente? :)
fonte
Nullable<X>
VisualStudio 2013 e o F12, verá que ele apenas sobrecarrega a conversão de e paraX
oEquals(object other)
método. No entanto, acho que o operador == usa esse método por padrão, portanto o efeito é o mesmo. Na verdade, eu pretendo atualizar essa resposta há algum tempo, mas sou preguiçoso e / ou ocupado. Este comentário terá que fazer por agora :)int? val = 42; val.GetType() == typeof(int)
). Portanto, não apenas é nula uma estrutura que pode ser igual a nula, como também muitas vezes não é nula! : D Da mesma maneira, quando você coloca um valor nulo em caixa, você está encaixotandoint
, nãoint?
- e quandoint?
não tem um valor, você obtém, emnull
vez de um valor nulo em caixa. Basicamente, significa raramente há qualquer sobrecarga do uso de anulável corretamente :)Null
um tipo no .NET? Você pode apontar para a parte da especificação CLR / C # onde foi dito? Nullables são bem definidos na especificação CLR, seu comportamento não é "implementação de uma abstração" - é um contrato . Mas se o melhor que você pode fazer é ataques ad hominem, divirta-se.No VB.Net. NÃO use "IsNot Nothing" quando puder usar ".HasValue". Acabei de solucionar um erro de confiança médio "A operação poderia desestabilizar o tempo de execução", substituindo "IsNot Nothing" por ".HasValue" em um único local. Eu realmente não entendo o porquê, mas algo está acontecendo de maneira diferente no compilador. Eu diria que "! = Null" em C # pode ter o mesmo problema.
fonte
HasValue
por causa da legibilidade.IsNot Nothing
é realmente uma expressão feia (por causa da dupla negação).Se você usa linq e deseja manter seu código curto, recomendo sempre usar
!=null
E é por isso que:
Vamos imaginar que temos alguma classe
Foo
com uma variável dupla anulávelSomeDouble
Se em algum lugar do código queremos obter todos os Foo com valores SomeDouble não nulos de uma coleção de Foo (supondo que alguns foos na coleção também possam ser nulos), terminamos com pelo menos três maneiras de escrever nossa função (se use C # 6):
E nesse tipo de situação eu recomendo sempre ir para a mais curta
fonte
foo?.SomeDouble.HasValue
é um erro em tempo de compilação (não um "lance" na minha terminologia) nesse contexto porque seu tipo ébool?
, não apenasbool
. (O.Where
método deseja aFunc<Foo, bool>
.) É permitido fazer isso(foo?.SomeDouble).HasValue
, é claro, desde que esse tipo sejabool
. É para isso que sua primeira linha é "traduzida" internamente pelo compilador C # (pelo menos formalmente).Resposta geral e regra geral: se você tiver uma opção (por exemplo, escrever serializadores personalizados) para processar Nullable em pipeline diferente de
object
- e usar suas propriedades específicas - faça-o e use propriedades específicas Nullable. Portanto, do ponto de vista do pensamento consistente,HasValue
deve ser preferido. O pensamento consistente pode ajudá-lo a escrever um código melhor, sem gastar muito tempo em detalhes. Por exemplo, o segundo método será muitas vezes mais eficaz (principalmente por causa dos compiladores embutidos e do boxe, mas os números ainda são muito expressivos):Teste de benchmark:
Código de referência:
https://github.com/dotnet/BenchmarkDotNet foi usado
PS . As pessoas dizem que o conselho "prefere o HasValue por causa de um pensamento consistente" não é relacionado e inútil. Você pode prever o desempenho disso?
PPS As pessoas continuam menos, mas ninguém tenta prever o desempenho de
CheckNullableGenericImpl
. E há compilador não irá ajudá-lo a substituir!=null
comHasValue
.HasValue
deve ser usado diretamente se você estiver interessado em desempenho.fonte
CheckObjectImpl
caixas são anuláveis em umobject
, enquantoCheckNullableImpl
que não usam boxe. Assim, a comparação é muito imprecisa. Além de não ser tarifa, também é inútil, porque, conforme observado na resposta aceita , o compilador reescreve!=
deHasValue
qualquer maneira.Nullable<T>
, você faz (encaixotando-o em umobject
). Quando você aplica!= null
com um valor nulo à esquerda, não ocorre boxe porque o suporte!=
para valores nulos funciona no nível do compilador. É diferente quando você oculta o valor anulável do compilador colocando-o primeiro em umobject
. Nem oCheckObjectImpl(object o)
seu benchmark faz sentido em princípio.CheckObjectImpl
com o seu corpo dentroCheckObject
. No entanto, seus comentários mais recentes revelam que você realmente tinha uma pergunta completamente diferente em mente quando decidiu responder a essa pergunta de 8 anos, o que torna sua resposta enganosa no contexto da pergunta original. Não era sobre o que o OP estava perguntando.what is faster != or HasValue
. Ele chega a essa pergunta, navega pela sua resposta, aprecia sua referência e diz: "Nossa, eu nunca vou usar!=
porque é claramente muito mais lento!" Essa é uma conclusão muito errada, a qual ele continuará se espalhando. É por isso que acredito que sua resposta é prejudicial - ela responde a uma pergunta errada e, assim, planta uma conclusão errada no leitor desavisado. Considere o que acontece quando você mudar o seuCheckNullableImpl
para também serreturn o != null;
Você vai obter o mesmo resultado benchmark.!=
eHasValue
quando, na verdade, mostra a diferença entreobject o
eT? o
. Se você fizer o que sugeri, ou seja, reescreverCheckNullableImpl
comopublic static bool CheckNullableImpl<T>(T? o) where T: struct { return o != null; }
, você terminará com uma referência que mostra claramente que!=
é muito mais lenta que!=
. Que deve levá-lo a conclusão de que a questão a sua resposta descreve não é sobre!=
vsHasValue
em tudo.