Até onde deve 'var' e operador coalescente nulo '??' se divertir sem prejudicar a legibilidade?


23

Eu sei que o título da pergunta é muito subjetivo, mas fui confrontado com o uso do ??operador por meus colegas, onde, ao mesmo tempo, não estava muito feliz / confortável em aplicar o varnovo código que estava por vir.

O argumento dado para o uso do ??operador foi que tira a legibilidade do código.

Minha pergunta é: não acontece o mesmo quando você começa a usar var?


49
Se um "desenvolvedor" não conseguir entender o ??operador de coalescência nula depois de explicado, não deverá ser permitido perto do código de produção.
CaffGeek

12
Sugiro que alteremos o operador de ?? para IfNullThen. ? pode ser IfSoChoose,: é ElseChoose. + é adicionar. - é Subtrair, a menos que seja unário, então é Negativo. - é dividido entre DecrementBeforeUsing e DecrementAfterUsing. Em C ++, você pode fazer isso com macros.
Lee Louviere

7
@Xaade: Isso é ironia, não é? ... direito? ... Deus, que seja ironia (e eu sou ateu).
Steven Jeuris

10
@StevenJeuris Pode ser sarcasmo , mas não é ironia .
precisa

1
@KirkBroadhurst: Estou corrigido , sempre confundi esses dois.
Steven Jeuris

Respostas:


53

Operador coalescente nulo (??)

Pessoalmente, não vejo desvantagens em usar esse operador. Considere os três exemplos de código a seguir, de novos operadores 'fáceis' a 'complexos'.

Sem mágica:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Operador ternário:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Combinação nula:

string name = null;
Console.WriteLine( name ?? "No name set." );

A razão pela qual esses operadores foram inventados é porque eles representam operações de programação muito comuns . Não querer usá-los porque você não está acostumado a eles é apenas ser teimoso . Idiomas evoluem, recursos evoluem, aprendem a usá-los!

palavra-chave var

Tenho uma opinião um pouco diferente sobre a palavra-chave var. O tipo de uma variável geralmente fornece informações extras sobre o seu código. Acho que ocultar o tipo usando a palavra-chave var às vezes torna o código menos legível. Você sabe menos o que esperar sem usar o preenchimento automático ou passar o mouse sobre os identificadores para ver o que eles realmente são. Na minha opinião, isso resulta em código que é mais lento para ler / escrever.

Eu uso a palavra-chave quando percebo que o tipo não fornece muita informação extra.

  • Principalmente nos loops foreach , que aprendi com o Resharper, pois é um cenário lá. Na maioria das vezes, você sabe que tipo de coleção você está percorrendo e, portanto, espera itens da coleção.
  • Consultas Linq . O resultado das consultas linq geralmente são tipos genéricos muito complexos. A exibição desse tipo faz mais mal do que bem.
  • Nomes longos de tipos que são simplesmente inicializados com seu construtor. Você já pode dizer qual é o tipo olhando para o construtor.

Como um exemplo para a última declaração:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();

24
Esse último exemplo é exatamente quando a palavra-chave var pode se destacar. Imagine que o código está espalhado por todo o código. Factory.CreateSomeTyperetorna IEnumerable<SomeType>. Um dia, por qualquer motivo, ele muda para retornar SomeType[]. Se você usou var, é apenas uma recompilação.
Pd #

1
Peguei esse exemplo da maneira errada e depois fui procurar comida. Numpty! Um exemplo melhor seria usar o seu. E se as Factory.CreateSomeType()alterações para retornar um ISomeType?
PDR

4
@pdr: Isso provavelmente significa que a interface também mudou, e o comportamento também precisa ser ajustado / adicionado. Se for uma renomeação simples, é claro que você renomeou automaticamente. Se o 'contrato' mudar, prefiro ver meu código quebrar, para ver se preciso ajustar algo ou não.
precisa

2
Eu acho que é muito mais provável que se retornar um tipo concreto retorne uma interface, apenas permita outros tipos concretos com a mesma interface (consistente com o padrão Factory). Mas se o contrato mudar, seu código será quebrado - embora você possa encontrá-lo apenas em alguns casos em que é importante e não em qualquer lugar.
PDR

1
@ Tom Hawtin, todos sabemos que é inevitável evitar nullcompletamente. Além disso, quanto mais procuro alternativas null, mais percebo que o uso nullàs vezes é a solução mais limpa. Meu exemplo não é tão ruim assim, e acho que é um uso apropriado de tipos anuláveis.
Steven Jeuris

16

var permite código menos detalhado, o que aumenta a legibilidade. Na minha opinião, a legibilidade não deve ser medida por quantos detalhes você vê, mas por quantos detalhes estão ocultos à primeira vista. Além dos exemplos do Linq, var permite digitação de patos no nível do código-fonte, conforme o exemplo a seguir:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Quem se importa com o tipo de rótulo, desde que ele forneça a propriedade Text?


Alguém tentando entender se isso é, por exemplo, um rótulo winforms ou um rótulo WPF.
Steven Jeuris

14
@ Steven Jeuris: isso geralmente é uma informação de contexto conhecida. Caso contrário, você está abordando o código de maneira errada.
Codism 16/03/11

Alguém que quer saber se é um rótulo WPF padrão ou algum rótulo personalizado então? :)
Steven Jeuris

14
1. Essa pessoa deve realmente se importar, desde que seja um rótulo com uma propriedade Text? 2. Se esse for um dos raros casos em que REALMENTE TÊM um bom motivo para se importar, pergunte ao Intellisense. 3. Se estiver editando código em um IDE sem Intellisense, eles provavelmente têm inconvenientes muito maior do que 'var' :)
KutuluMike

4
Alguém com um pobre senso de abstração.
Jim Balter

16

Não tenho nenhum comentário sério sobre o ??operador, pois nunca usei muito um idioma com esse operador. Em relação a isso var, as pessoas programam em linguagens como Ruby, Python, Perl e PHP que têm digitação totalmente implícita o tempo todo. Os nativos dessas línguas percebem que o tipo formal de uma variável é geralmente ruído irrelevante. Você está mais interessado no que a variável pode fazer , ou seja, sua interface estrutural / duck.

Da mesma forma, eu programa principalmente em D. D é digitado estaticamente, mas tem a autopalavra - chave, que é equivalente a var. É considerado idiomático usá-lo em qualquer lugar, a menos que você veja uma necessidade específica de enfatizar o tipo de algo para o leitor ou (por conversão implícita) para o compilador. Exceto ocasionalmente quando usado como um tipo de retorno de função (isso é permitido em D), nunca achei que isso prejudicasse a legibilidade, porque penso principalmente em termos de interfaces estruturais / de pato, e não de tipos formais / nominativos, quando programa.

Além disso, o IMHO usando sempre que varpossível é um bom exemplo de DRY. O tipo de algo deve ser especificado em um e apenas um local e, em seguida, ser propagado automaticamente sempre que precisar. Se você usar vare o tipo formal da variável precisar mudar em algum momento, as alterações necessárias serão propagadas automaticamente em todos os lugares necessários pelo compilador, desde que o programa ainda esteja correto, em vez de o programador precisar alterar manualmente todas as instâncias . Esta é uma coisa boa (TM).


13

Eu acho que essa é uma pergunta para a equipe no final. Se não for legível para mais ninguém da minha equipe, não o utilizarei, embora tente algumas vezes convencê-los com exemplos ou apontando abreviações análogas (como + =) que considerem mais legíveis.

No entanto, se trabalhar sozinho, então eu acho? e var eminentemente legível sem limites. Até

var a = b ?? c ?? d ?? e ?? "";

é bastante inequívoco para mim.

Operadores ternários e dynamicsão uma questão diferente, é claro.


4
Eu usaria `String.Empty 'aqui.
Job

1
@Job, honestamente, eu também. Eu ia colocar algo nessa string, então não conseguia pensar em nada :)
pdr

4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere

2
@ Xaade Você nunca pode ter certeza. Mas, na verdade, usar String.Empty ou "" é uma preferência pessoal. Eu uso "" porque é mais curto ...
Carra

12
@ Xaade - se String.Emptyalguma vez retornar null, estamos com um monte de códigos quebrados.
Jesse C. Slicer

10

O argumento dado para usar ?? operador era, tira a legibilidade no código.

Pensando brevemente, esse comentário me diz que a pessoa que está fazendo o comentário não o entende tão bem quanto deveria. Provavelmente é verdade em determinadas situações, mas, no geral, não descarto algo que a equipe do C # obviamente tenha considerado importante o suficiente para adicionar devido à "legibilidade". Eu coloquei isso na mesma categoria de if(boolean_object)vs if(boolean_object == true). Algumas pessoas argumentam que o segundo é mais legível, mas, na realidade, é apenas adicionar código extra para alguém ler / digitar e, em algumas situações, pode ser mais confuso (pense if(boolean_object != false))

Minha pergunta é: não acontece o mesmo quando você começa a usar var?

A equipe de C # permitiu que você não definisse algo que você sabe o que será. A menos que eu precise absolutamente definir o que uma variável será (ou é absolutamente importante que um objeto retornado seja do tipo x ou realmente não seja legível), eu uso var. var x = "MY_STRING";Eu sei que é uma corda de olhar para ele. Na verdade, eu realmente não me importo que seja uma corda, desde que faça o que eu preciso. Definir o tipo de variável é para meu benefício, não o compilador. Se algo estiver errado, o compilador informará quando é executado se eu tiver o tipo de variável errado.


0

A varpalavra-chave é, na minha opinião, usada melhor nas situações para as quais foi introduzida original - consultas LINQ. Nessas consultas, o tipo do resultado retornado geralmente possui um nome grande e complicado que é difícil de determinar com antecedência e não ajuda o leitor a entender o que seu código faz.

No entanto, fazer var text = "Some text " + variableName + "some more text."é apenas preguiçoso.

EDIT: @Jorg Você pulou em uma resposta propositadamente simplista, mas não adicionou nada à discussão. OK, que tal um exemplo melhor: var items = doc.DocumentElement.FirstChild.ChildNodes;se você puder descobrir o tipo a partir disso, darei um cookie.


18
Se você não conseguir descobrir que "Some text "é a string, terá problemas muito maiores com o que o número de vars no seu código.
Jörg W Mittag

3
O problema não é var; o problema é o nome da variável de baixa qualidade "itens". Se você usar um bom nome de variável, não há nada errado var.
Kyralessa 10/11

3
Estou supondo (sem olhar) que itens é uma coleção de nós XML, que espero ter todas as propriedades e métodos de uma coleção de nós XML, e isso é tudo o que preciso saber.
KutuluMike

Se você precisar saber qual o tipo de var e não saber dizer imediatamente, basta passar o mouse sobre ele. Não é preciso muito esforço para fazê-lo.
Scrwtp

1
"é apenas preguiçoso" - este não é um argumento contra. De fato, não é de todo inteligente.
Jim Balter

0

Eu tenho um problema fundamental com o uso de var.

Neste exemplo, tudo fica lado a lado, mas o problema é realmente com grandes soluções com bibliotecas ou projetos compartilhados.

Considere isto:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

O que acontece se GetMeAnObject for alterado, por outra pessoa, para atender às suas necessidades?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

O método MainProgram terá um grande erro vermelho em .PerformOperation (). O que aconteceu? PerformOperation funcionou perfeitamente bem antes. Observamos os métodos no objeto e ele simplesmente desapareceu sem deixar rasto. Foi lá da última vez, e precisamos desse método. Você pode gastar muito tempo perseguindo seu rabo e tentando descobrir por que, se MyFirstObject possui um método chamado PerformOperation, ele agora não pode ser visto. Todo mundo "sabe" que GetMeAnObject retorna um MyFirstObject, então não faz sentido verificar isso.

Se você tivesse digitado explicitamente theObject, teria um erro de Invalid Cast na linha que chama GetMeAnObject, e seria óbvio que GetMeAnObject está retornando um tipo que não é o que você espera.

Em resumo, declaração explícita significa que você sabe o que significam os erros. Uma conversão inválida significa que você esperava um tipo e outro tipo foi retornado. Um membro não reconhecido significa que o membro não foi reconhecido.


10
Um colega de trabalho fez uma alteração no código não coberta por testes e você acha que o problema é var? Não se espera que o idioma proteja esse tipo de comportamento - e se eles tivessem modificado o MyFirstObject diretamente? Ainda estaria quebrado, mas nenhuma sintaxe poderia ter salvado você disso. Eu consideraria isso uma força de varaté: e se, em vez de retornar o MySecondObject, você agora estivesse retornando o IMyFirstObject?
Phoshi

2
"Todo mundo" sabe "que GetMeAnObject retorna um MyFirstObject, então não faz sentido verificar isso." Na verdade, não consigo pensar em um cenário de programação em que realmente dependa da minha memória do que GetMeAnObject se estiver depurando. Se eu verifiquei que o PerformOperation não está lá, eu teria visto o código e não, é para outra classe. Se em um IDE a classe iria aparecer a instância, eu olho para o tipo do objeto. Na verdade, quando o compilador me diz o erro, ele diria 'classe MySecondObject não tem operação PerformOperation'. Como é isso para todo mundo sabe?
Muhammad Alkarouri
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.