O que usar: tipo de nome var ou object?

essa é uma pergunta que quando estou programando sempre me pergunto: O que usar quando estamos escrevendo código:

var myFiles = Directory.GetFiles(fullPath); 

ou

 string[] myFiles = Directory.GetFiles(fullPath); 

var é novo e é uma variável local digitada implicitamente , então só podemos usar localmente e tem regras como não pode ser nulo, etc, mas eu me pergunto se temos alguma vantagem de usá-lo “normalmente”.

A parte “normal” diz, não em Tipos Anônimos , Inicializadores de Objetos e Coleções e Expressões de Consulta onde a intenção era usar o object var anônimo, então o que quero dizer é … assim como no exemplo acima.

Quais são seus pensamentos?

Além do uso óbvio de var com o LINQ, eu também o uso para abreviar declarações de variables ​​para legibilidade, por exemplo:

 var d = new Dictionary>>(); 

Em geral, eu recebo uma espécie de conforto (por falta de uma palavra melhor) da tipagem estática que me faz relutar em desistir. Eu gosto da sensação de que sei o que estou fazendo quando estou declarando uma variável. Declarar uma variável não é apenas dizer ao compilador algo, é dizer à pessoa que está lendo seu código.

Deixe-me lhe dar um exemplo. Suponha que eu tenha um método que retorne uma List . Este código é certamente correto, e eu acho que é como 90% dos desenvolvedores C # provavelmente escreveriam:

 List list = MyMethod(); 

Obviamente, certo? Na verdade, aqui está um lugar que você poderia facilmente usar var .

Verdade suficiente. Mas esta versão do código não está apenas declarando uma variável, está me dizendo o que a pessoa que a escreveu está pretendendo fazer:

 IEnumerable list = MyMethod(); 

O desenvolvedor que escreveu esse código está me dizendo: “Não vou alterar essa lista, nem usarei um índice para acessar seus membros. Tudo o que vou fazer é iterá-la”. Isso é muita informação para transmitir em uma única linha de código. É algo que você desiste se usar var .

Claro, você não está desistindo se você não estava usando isso em primeiro lugar. Se você é o tipo de desenvolvedor que escreveria essa linha de código, você já sabe que não usaria var lá.

Editar:

Eu acabei de reler o post de Jon Skeet, e essa citação de Eric Lippert me chamou a atenção:

Os locais com nomes implícitos são apenas uma pequena maneira em que você pode desvalorizar o como e, assim, enfatizar o quê.

Eu acho que, na verdade, em muitos casos, usando digitação implícita está deixando o que implícito. Não há problema em não me debruçar sobre o quê. Por exemplo, eu escrevo casualmente uma consulta LINQ como:

 var rows = from DataRow r in parentRow.GetChildRows(myRelation) where r.Field("Flag") orderby r.Field("SortKey") select r; 

Quando eu leio esse código, uma das coisas que eu acho quando estou lendo é ” rows é um IEnumerable .” Porque eu sei que o que as consultas LINQ retornam é IEnumerable , e eu posso ver o tipo do object sendo selecionado ali mesmo.

Esse é um caso em que o que não foi explicitado. Foi deixado para mim inferir.

Agora, em cerca de 90% dos casos em que uso o LINQ, isso não importa nem um pouquinho. Porque 90% do tempo, a próxima linha de código é:

 foreach (DataRow r in rows) 

Mas não é difícil imaginar código em que seria muito útil declarar rows como IEnumerable – código em que muitos tipos diferentes de objects estavam sendo consultados, não era possível colocar a declaração de consulta ao lado da iteração , e seria útil poder inspecionar rows com o IntelliSense. E isso é uma coisa, não uma coisa como.

Você terá uma enorme variedade de opiniões sobre isso – de “usar var em todos os lugares” para “usar apenas var com tipos anônimos, onde você basicamente precisa.” Eu gosto da opinião de Eric Lippert sobre isso :

Todo o código é uma abstração. O que o código está “realmente” fazendo é manipular dados? Não. Números? Bits? Não. Voltagens? Não. Elétrons? Sim, mas entender o código no nível dos elétrons é uma má ideia! A arte de codificar é descobrir qual é o nível correto de abstração para o público.

Em uma linguagem de alto nível, há sempre essa tensão entre o que o código faz (semanticamente) e como o código faz isso. Os programadores de manutenção precisam entender o que e o como, se conseguirão fazer mudanças com sucesso.

O ponto principal do LINQ é que ele enfatiza enfaticamente o “como” e enfatiza maciçamente o “o quê”. Usando uma compreensão de consulta, o programador está dizendo para o futuro público “Eu acredito que você não deve saber nem se importar exatamente como este conjunto de resultados está sendo calculado, mas você deve se importar muito sobre o que é a semântica do conjunto resultante.” Eles tornam o código mais próximo do processo de negócios que está sendo implementado e mais longe dos bits e elétrons que o fazem.

Os locais com nomes implícitos são apenas uma pequena maneira em que você pode desvalorizar o como e, assim, enfatizar o quê. Se isso é a coisa certa a fazer em um caso particular é um julgamento. Então eu digo às pessoas que se o conhecimento do tipo é relevante e sua escolha é crucial para a operação continuada do método, então não use tipagem implícita. A digitação explícita diz “Estou lhe dizendo como isso funciona por um motivo, preste atenção”. Digitação implícita diz “não importa nem um pouco se isso é uma lista ou um cliente [], o que importa é que é uma coleção de clientes”.

Pessoalmente, não costumo usá-lo se o tipo não for razoavelmente óbvio – onde incluo as consultas LINQ como “razoavelmente óbvias”. Eu não faria isso por Directory.GetFiles por exemplo, já que não é realmente óbvio que isso retorna uma string[] invés de (digamos) um FileInfo[] (ou algo totalmente diferente) – e isso faz uma grande diferença para o que você fazer mais tarde.

Se houver uma chamada de construtor no lado direito do operador de atribuição, estou muito mais propenso a usar o var : é claramente óbvio qual será o tipo. Isso é particularmente útil com tipos genéricos complexos, por exemplo, Dictionary> .

Pessoalmente eu só uso var em dois lugares:

  1. Com tipos anônimos, ou seja. Relacionado ao LINQ (em que var é necessário em alguns casos)
  2. Quando a declaração declara e constrói um tipo específico no mesmo tipo

ie. Este é um exemplo do ponto 2:

 var names = new List(); 

Editado : Isso em resposta à pergunta de Jon Skeet.

A resposta acima foi de fato simplificada. Basicamente, eu uso var onde o tipo é:

  1. Desnecessário saber (não muitos lugares embora)
  2. Impossível saber (LINQ, tipos anônimos)
  3. Caso contrário, conhecido ou claro no código

No caso de um método de fábrica, onde tudo que você precisa saber no lugar onde você escreve o código é que o object que você recebe é um descendente de algum tipo, e que algum tipo tem um método de fábrica estático, então eu usaria var . Como isso:

 var connection = DatabaseConnection.CreateFromConnectionString("..."); 

O exemplo acima é um exemplo real do meu código. É claro, pelo menos para mim e para as pessoas que usam esse código, que a conexão é um descendente DatabaseConnection, mas o tipo exato não é necessário nem para entender o código nem para usá-lo.

Eu tentei o estilo “use var everywhere” … e é por isso que eu não continuei a usá-lo.

  1. Legibilidade degradada às vezes
  2. Limites de IntelliSense depois de =
  3. Digitar “var” não era muito mais curto do que digitar “int”, “string”, etc., especialmente com intellisense.

Com isso dito, eu ainda uso com o LINQ.

Vindo da terra da functional programming, onde as regras de inferência de tipos do dia, eu uso var para todos os locais, sempre que possível.

No Visual Studio, se você já se perguntou qual é o tipo de qualquer local, tudo o que você precisa fazer é passar o mouse sobre ele.

Este post tem algumas boas diretrizes sobre quando usar interface do tipo var ou tipos de objects.

Eu costumo usar var todos os lugares, mas meus colegas de trabalho disseram que parar, é menos legível para nós. Então eu agora uso var apenas em tipos anônimos, consultas LINQ e onde é construtor no lado direito.

Eu acho interessante notar como isso geralmente é tratado em Haskell. Graças ao isomorfismo de Curry-Howard , o tipo (mais geral) de qualquer expressão em Haskell pode ser inferido e, portanto, as declarações de tipo não são essencialmente necessárias em nenhum lugar, com algumas exceções; Por exemplo, às vezes você deliberadamente deseja limitar o tipo a algo mais específico do que seria inferido.

Naturalmente, o que é necessário e o que é recomendado não são a mesma coisa; na prática, a convenção parece ser que as definições de nível superior sempre têm declarações de tipo, enquanto as definições localizadas têm as declarações de tipo omitidas. Isso parece encontrar um bom equilíbrio entre a explicitação para a legibilidade da definição como um todo, em contraste com a brevidade para a legibilidade das definições “auxiliares” ou “temporárias” locais. Se bem entendi, você não pode usar var para definições de “nível superior” (como um método ou function global) em primeiro lugar, então eu acho que isso se traduz em “usar var todos os lugares que você pode” no c # world. É claro que digitar ” int ” é o mesmo número de pressionamentos de tecla que ” var “, mas a maioria dos exemplos será mais longa que isso.