O operador de coalescência nula em c # permite reduzir o código
if (_mywidget == null)
return new Widget();
else
return _mywidget;
Até:
return _mywidget ?? new Widget();
Eu continuo achando que um operador útil que eu gostaria de ter em C # seria aquele que lhe permitisse retornar uma propriedade de um objeto ou algum outro valor se o objeto for nulo. Então eu gostaria de substituir
if (_mywidget == null)
return 5;
else
return _mywidget.Length;
Com:
return _mywidget.Length ??! 5;
Não consigo deixar de pensar que deve haver alguma razão para esse operador não existir. É um cheiro de código? Existe alguma maneira melhor de escrever isso? (Estou ciente do padrão de objeto nulo, mas parece um exagero usá-lo para substituir essas quatro linhas de código.)
c#
code-smell
null
Ben Fulton
fonte
fonte
??!
é um operador em C ++. :-)Respostas:
Eu quero muito um recurso de linguagem C # que permita executar com segurança x.Prop.SomeOtherProp.ThirdProp sem precisar verificar nulo em cada um deles. Em uma base de código em que eu tive que fazer muito esses tipos de "percursos de propriedade profunda", escrevi um método de extensão chamado Navigate que engoliu NullReferenceExceptions e, em vez disso, retornou um valor padrão. Então eu poderia fazer algo assim:
A desvantagem disso é que ele tem um cheiro de código diferente: exceções engolidas. Se você quiser fazer algo assim "certo", poderá usar o lamdba como uma expressão e modificar a expressão rapidamente para adicionar as verificações nulas em torno de cada acessador de propriedade. Eu fui "rápido e sujo" e não o implementei dessa maneira "melhor". Mas talvez, quando eu tiver alguns ciclos de pensamento de reserva, revisite e publique em algum lugar.
Para responder mais diretamente à sua pergunta, acho que o motivo não é um recurso, porque o custo de implementação do recurso excede o benefício de ter o recurso. A equipe de C # precisa escolher quais recursos focar, e esse ainda não chegou ao topo. Apenas um palpite, embora eu não tenha nenhuma informação privilegiada.
fonte
Acredito que você poderá fazer isso com o C # 6 agora:
Observe o operador condicional nulo
?.
no lado esquerdo._mywidget?.Length
retorna nulo se_mywidget
for nulo.Um operador ternário simples pode ser mais fácil de ler, como outros sugeriram.
fonte
Na verdade, é apenas especulação sobre o motivo de não terem feito isso. Afinal, eu não acredito? estava na primeira versão do C #.
De qualquer forma, eu usaria o operador condicional e o chamaria de dia:
O ?? é apenas um atalho para o operador condicional.
fonte
5
a resposta, caso não esteja lá. Você precisa observar o seu design antes de começar a solicitar operadores especiais.Parece com o operador ternário:
fonte
Pessoalmente, acho que isso se deve à legibilidade. No primeiro exemplo, o
??
traduz muito bem como "Você está aí? Não, vamos fazer isso".No segundo exemplo,
??!
é claramente WTF e não significa nada para o programador .... o objeto não existe, então não consigo chegar à propriedade, então retornarei 5. O que isso significa? O que é 5? Como chegamos à conclusão de que 5 é um bom valor?Em suma, o primeiro exemplo faz sentido ... não existe, é novo . No segundo, está aberto ao debate.
fonte
(foo() != ERROR)??!??! cerr << "Error occurred" << endl;
.)5
. Eu realmente acho que há mais um problema que você precisa fazer assim, enquanto no seu primeiro exemplo, a necessidade é bastante óbvia, especialmente em coisas como gerenciadores de cache.Eu acho que as pessoas estão muito envolvidas no "5" que você está retornando ... talvez 0 fosse melhor :)
Enfim, acho que o problema é que na
??!
verdade não é um operador independente. Considere o que isso significa:Nesse caso, não faz sentido: só faz sentido se o operando do lado esquerdo for um acessador de propriedades. Ou então:
Há um acessador de propriedades lá, mas ainda acho que não faz sentido (se
myWidget
énull
, isso significa que não ligamosFoo()
?), Ou isso é apenas um erro?Eu acho que o problema é que simplesmente não se encaixa tão naturalmente na língua quanto o
??
faz.fonte
Alguém criou uma classe de utilidade que faria isso por você. Mas não consigo encontrar. O que encontrei foi semelhante nos fóruns do MSDN (veja a segunda resposta).
Com um pouco de trabalho, você pode estendê-lo para avaliar chamadas de método e outras expressões que a amostra não suporta. Você também pode estendê-lo para aceitar um valor padrão.
fonte
Eu entendo de onde você está vindo. Parece que todo mundo está se envolvendo no eixo com o exemplo que você forneceu. Embora eu concorde que os números mágicos sejam uma péssima idéia, seria usado o equivalente a um operador de coalescência nulo para determinadas propriedades.
Por exemplo, você tem objetos vinculados a um mapa e deseja que eles estejam na elevação adequada. Os mapas DTED podem ter buracos em seus dados, portanto, é possível ter um valor nulo, além de valores na faixa de algo entre -100 a ~ 8900 metros. Você pode querer algo como:
O operador de coalescência nula nesse caso preencheria a altitude padrão se as coordenadas ainda não estivessem definidas ou o objeto Coordenadas não pudesse carregar dados DTED para esse local.
Eu vejo isso como muito valioso, mas minha especulação sobre o motivo de não ter sido feito é limitada à complexidade do compilador. Pode haver alguns casos em que o comportamento não seria tão previsível.
fonte
Quando não estou lidando com aninhamentos profundos, usei isso (antes do operador coalescente nulo introduzido no C # 6). Para mim, é bem claro, mas talvez seja porque eu estou acostumado, outras pessoas podem achar isso confuso.
Obviamente, isso nem sempre é aplicável, pois às vezes a propriedade que você precisa acessar não pode ser definida diretamente ou quando a construção do objeto em si é cara, entre outros motivos.
Outra alternativa é usar o padrão NullObject . Você define uma única instância estática da classe com valores padrão sensíveis e usa-a.
fonte
Números mágicos são geralmente um cheiro ruim. Se o 5 for um número arbitrário, é melhor explicá-lo para que seja documentado com mais clareza. Uma exceção na minha opinião seria se você tiver uma coleção de valores que estão atuando como valores padrão em um contexto específico.
Se você tiver um conjunto de valores padrão para um objeto, poderá subclassificá-lo para criar uma instância singleton padrão.
Algo como: return (myobj ?? default_obj) .Length
fonte
A propriedade Length geralmente é um tipo de valor, portanto, não pode ser nulo; portanto, o operador de coalescência nula não faz sentido aqui.
Mas você pode fazer isso com uma propriedade que é um tipo de referência, por exemplo:
var window = App.Current.MainWindow ?? new Window();
fonte
Eu já vi alguém com uma idéia semelhante antes, mas na maioria das vezes você também deseja atribuir o novo valor ao campo nulo, algo como:
então a ideia era combinar a atribuição
??
e=
em:Eu acho que isso faz mais sentido do que usar um ponto de exclamação.
Essa ideia não é minha, mas eu realmente gosto :)
fonte
return _obj ?? new Class();
não seja necessário o??=
aqui.