Uso da palavra-chave var em C #

406

Após uma discussão com os colegas sobre o uso da palavra-chave 'var' no C # 3, perguntei-me qual seria a opinião das pessoas sobre os usos apropriados da inferência de tipo via var?

Por exemplo, usei preguiçosamente var em circunstâncias questionáveis, por exemplo: -

foreach(var item in someList) { // ... } // Type of 'item' not clear.
var something = someObject.SomeProperty; // Type of 'something' not clear.
var something = someMethod(); // Type of 'something' not clear.

Os usos mais legítimos de var são os seguintes: -

var l = new List<string>(); // Obvious what l will be.
var s = new SomeClass(); // Obvious what s will be.

Curiosamente, o LINQ parece ser um pouco de uma área cinzenta, por exemplo: -

var results = from r in dataContext.SomeTable
              select r; // Not *entirely clear* what results will be here.

Está claro quais serão os resultados, pois será um tipo que implementa IEnumerable, no entanto, não é totalmente óbvio da mesma maneira que um var que declara um novo objeto.

É ainda pior quando se trata de LINQ para objetos, por exemplo: -

var results = from item in someList
              where item != 3
              select item;

Isso não é melhor que o equivalente foreach (var item em someList) {// ...}.

Há uma preocupação real com a segurança do tipo aqui - por exemplo, se colocarmos os resultados dessa consulta em um método sobrecarregado que aceite IEnumerable <int> e IEnumerable <double>, o chamador poderá inadvertidamente passar para o tipo errado.

var não manter a tipagem forte, mas a questão é realmente se é perigoso para o tipo de não ser imediatamente aparente na definição, algo que é ampliada quando sobrecargas erros do compilador médios não pode ser emitido quando você involuntariamente passar o tipo errado para um método.

ljs
fonte
68
Usar var é bom, mas "Eu não preciso descobrir o tipo" parece uma péssima razão para usá-lo ... você deveria saber qual é o tipo, var é apenas um atalho para evitar digitá-lo
Thomas Levesque
53
var i = 0;== falha! var c = new CrazyFrigginLongClassName();== ganhar!
Dotjoe 19/05
6
"O Var também me lembra o tipo de variante VB / VBA. Ele também tinha seu lugar. Lembro-me (de muitos anos atrás) de seu uso ser do tipo menos do que o desejável e consumia bastante recursos". <- mostra que esta é uma pergunta interessante, pois o tipo 'var' de C # não tem nada a ver com o tipo de variante VB / VBA.
User7116
20
var readabilityBeDamned = true;
Spoulson 19/05/10
9
O problema com todos os exemplos declarados aqui é que estamos vendo uma linha de código. Quando vejo linha após linha das declarações "var", uma após a outra, fica fora de controle. A legibilidade é subjetiva, mas acho que o var abusou muito mais do que o usado de forma respeitável.
JRO

Respostas:

293

Eu ainda acho que varpode tornar o código mais legível em alguns casos. Se eu tiver uma classe Customer com uma propriedade Orders e desejar atribuí-la a uma variável, farei isso:

var orders = cust.Orders;

Eu não me importo se Customer.Orders é IEnumerable<Order>, ObservableCollection<Order>ou BindingList<Order>- tudo o que eu quero é manter essa lista na memória para iterá-la ou obter sua contagem ou algo mais tarde.

Compare a declaração acima com:

ObservableCollection<Order> orders = cust.Orders;

Para mim, o nome do tipo é apenas ruído. E se eu voltar e decidir mudar o tipo de Customer.Orders abaixo da faixa (digamos de ObservableCollection<Order>para IList<Order>), também preciso alterar essa declaração - algo que não precisaria fazer se tivesse usado var no primeiro Lugar, colocar.

Matt Hamilton
fonte
48
Eu gosto de ter o tipo explícito na minha frente quando estou lendo o código. Como sei o que "cust.Orders" está aqui sem o tipo? Sim, eu poderia passar o mouse sobre para descobrir, mas por que devo? :)
Jon Tackabury
77
Mas o ponto é que, em geral, isso não importa. Cust.Orders são algo que você pode enumerar (por exemplo, foreach over); então, não importa que tipo seja. O código extra apenas atrapalha a leitura da intenção.
Matt Hamilton
67
Mas se você precisar apenas de cust.Orders é "algo que você pode enumerar", não o declarará como um IEnumerable <Order> tornará esse requisito explícito e claro? Declará-lo como var significa que você efetivamente perde esse requisito.
Grahams
5
@jon e como IEnumerbal orders = cust.Orders foreach (var order in orders) fazem a diferença? a única coisa que o IEnumerable diz é que você pode colocá-lo em um foreach, mas você já sabia disso a partir da linha abaixo
Rune FS
18
"a única coisa que o IEnumerable diz é que você pode colocá-lo em um foreach" - também expressa a intenção de que a única coisa que você pode fazer é enumerar. O uso de var fornece acesso e intellisense para membros públicos do tipo de coleção concreta.
31410 Joe
167

Eu uso varextensivamente. Houve críticas de que isso diminui a legibilidade do código, mas nenhum argumento para apoiar essa afirmação.

É certo que pode significar que não está claro com que tipo estamos lidando. E daí? Este é realmente o ponto de um design dissociado. Ao lidar com interfaces, você enfaticamente não está interessado no tipo de variável. varisso leva muito mais longe, é verdade, mas acho que o argumento permanece o mesmo do ponto de vista da legibilidade: o programador não deveria estar realmente interessado no tipo da variável, mas no que uma variável faz . É por isso que a Microsoft também chama a inferência de tipo de "digitação de pato".

Então, o que uma variável faz quando a declaro usando var? Fácil, ele faz o que o IntelliSense me diz que faz. Qualquer raciocínio sobre C # que ignora o IDE fica aquém da realidade. Na prática, todo código C # é programado em um IDE que suporta o IntelliSense.

Se eu estiver usando uma varvariável declarada e ficar confuso para o que a variável existe, existe algo fundamentalmente errado no meu código. varnão é a causa, apenas torna os sintomas visíveis. Não culpe o mensageiro.

Agora, a equipe do C # lançou uma diretriz de codificação afirmando que var deve ser usada para capturar o resultado de uma instrução LINQ que cria um tipo anônimo (porque aqui, não temos uma alternativa real ). Bem, que se dane. Enquanto a equipe de C # não me der um argumento sólido para essa diretriz, vou ignorá-la porque, na minha opinião profissional e pessoal, é pura bobagem. (Desculpe, não tenho nenhum link para a diretriz em questão.)var

Na verdade, existem algumas (superficialmente) boas explicações sobre por que você não deve usar, varmas ainda acredito que elas estão amplamente erradas. Tomemos o exemplo de “capacidade de busca”: o autor alega que vardificulta a busca por locais onde MyTypeé usada. Direita. O mesmo acontece com as interfaces. Na verdade, por que eu gostaria de saber onde a classe é usada? Talvez eu esteja mais interessado em onde é instanciado e isso ainda poderá ser pesquisado porque em algum lugar seu construtor precisa ser chamado (mesmo que isso seja feito indiretamente, o nome do tipo deve ser mencionado em algum lugar).

Konrad Rudolph
fonte
14
Em qualquer IDE decente, você não usa uma pesquisa de texto para obter o uso da classe; o IDE faz isso com base em sua árvore de análise ou, no entanto, identifica os tipos de objetos. Como estamos falando de digitação estática, isso encontrará tudo, exceto os tipos anônimos.
Dustman
6
Eu odiaria herdar 100k linhas de fonte sem documentação e uso liberal de var. Especialmente se você combinar var com nomes de variáveis ​​pouco úteis. Eu pude ver isso útil ao ilustrar um ponto (ou lidar com tipos anônimos), mas no código de produção?
Shea
7
Arnshea: bem, você já apontou para o problema real: os nomes de variáveis inúteis e a documentação ausente . Eu realmente não vejo o que varcontribui para a confusão. Certamente, pode haver casos em que é importante enfatizar o tipo / tamanho de uma variável (por exemplo, operações de bit de baixo nível). Tudo bem: nunca ninguém afirmou que vardeveria ser usado exclusivamente. A regra é simples: se realmente causar confusão, não a use.
Konrad Rudolph
17
Todo exemplo oposto ao var que eu vi presume que o programador estará usando nomes de variáveis ​​sem sentido. Mas talvez seja por isso que var seja melhor do que especificar explicitamente um tipo: força o programador a criar bons nomes de variáveis.
21711 Ryan Lundy
16
A Microsoft também chama a inferência de tipo de "digitação de pato". - eles realmente? Eu ficaria chocado ...
Anton Tykhyy
118

Var, na minha opinião, em C # é uma coisa boa tm . Qualquer variável assim digitada ainda é fortemente digitada, mas ela obtém seu tipo do lado direito da atribuição em que está definida. Como as informações de tipo estão disponíveis no lado direito, na maioria dos casos, é desnecessário e excessivamente detalhado também ter que digitá-las no lado esquerdo. Eu acho que isso aumenta significativamente a legibilidade sem diminuir a segurança do tipo.

Na minha perspectiva, o uso de boas convenções de nomenclatura para variáveis ​​e métodos é mais importante do ponto de vista da legibilidade do que informações explícitas do tipo. Se eu precisar das informações de tipo, sempre posso passar o mouse sobre a variável (no VS) e obtê-la. Geralmente, porém, informações explícitas do tipo não devem ser necessárias para o leitor. Para o desenvolvedor, no VS, você ainda obtém o Intellisense, independentemente de como a variável é declarada. Dito tudo isso, ainda pode haver casos em que faz sentido declarar explicitamente o tipo - talvez você tenha um método que retorne a List<T>, mas queira tratá-lo como umIEnumerable<T>no seu método. Para garantir que você esteja usando a interface, declarar a variável do tipo de interface pode tornar isso explícito. Ou, talvez, você queira declarar uma variável sem um valor inicial - porque ela obtém imediatamente um valor com base em alguma condição. Nesse caso, você precisa do tipo. Se as informações de tipo forem úteis ou necessárias, vá em frente e use-as. Porém, sinto que normalmente não é necessário e o código é mais fácil de ler sem ele na maioria dos casos.

tvanfosson
fonte
3
Eu concordo em geral. O ponto-chave aqui na minha opinião é ter certeza de que a intenção é clara. Se não está claro para a maioria dos desenvolvedores da equipe, isso é prejudicial, não é útil. Dito isto, eu pessoalmente sou um grande fã disso, mas tive que me controlar um pouco quando outros desenvolvedores da minha equipe tiveram problemas para determinar minha intenção. Vai saber.
Steve Brouillard
3
É mais fácil ler quando o tipo está à esquerda. Usando o ReSharper, não preciso digitar novamente o tipo à direita, para que não me incomode.
BlueRaja - Danny Pflughoeft
1
@BlueRaja - Acho que o uso de bons nomes de variáveis ​​geralmente elimina a necessidade de se preocupar com o tipo real de qualquer maneira para a compreensão. O Intellisense ainda está disponível nas variáveis ​​definidas "var", portanto, não preciso saber o tipo para escolher um método / propriedade ao codificar.
Tvanfosson 19/05/10
2
Não é tanto sobre quando você está codificando, mas quando você precisa ler o código.
BlueRaja - Danny Pflughoeft
1
Devo estar do lado mais grosso, preciso de bons nomes de métodos e variáveis e uma compreensão dos tipos que estão sendo operados para poder entender corretamente o código que estou lendo. Eu acho que você está certo, embora seja sintomático de problemas maiores. Um de confiança. Para ter certeza de que o código está fazendo o que parece estar fazendo, você precisa ter certeza dos tipos que estão sendo usados.
AnthonyWJones
91

Nenhuma delas é absolutamente verdadeira; varpode ter efeitos positivos e negativos na legibilidade. Na minha opinião, vardeve ser usado quando uma das seguintes situações for verdadeira:

  1. O tipo é anônimo (bem, você não tem escolha aqui, pois deve ser var neste caso)
  2. O tipo é óbvio com base na expressão atribuída (ie var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating())

varnão tem impacto no desempenho, pois é açúcar sintático; o compilador infere o tipo e o define quando compilado em IL; não há nada realmente dinâmico nisso.

Adam Robinson
fonte
1
concordo com os dois, apesar de eu ter longas restrições sobre o segundo caso, se um tipo é tão longo que geralmente é um tipo genérico com muitos argumentos genéricos aninhados, nesse caso, um "ShortType equivalente a TypeWithAReallyLongNameTheresNoSenseRepeating" faz mais sentido
Ion Todirel 19/05
12
Não tenho desejo de iniciar uma guerra religiosa, mas, pessoalmente, tendem a discordar de Ion. Eu preferiria um nome de tipo muito longo, mas muito preciso (ala Tio Bob Martin) a um nome de tipo abreviado e possivelmente ambíguo. Acrescentarei a ressalva de que também não concordo em aumentar artificialmente o tamanho do nome. Se 5 caracteres cria um nome conciso que mostra claramente a intenção, em seguida, usar 5 e não 25.
Steve Brouillard
2
@ Steve: Eu tenho que concordar com você; criar um "tipo abreviado" (que suponho que você herda do tipo genérico específico apenas com o objetivo de encurtar o nome) não é uma boa prática; exigirá que você duplique e passe por qualquer construtor do tipo genérico, além de impedir que você passe um tipo diferente que herda do tipo genérico para a função. Você está usando herança como typedefquando não está.
Adam Robinson
7
Use varquando o tipo é óbvio? Talvez, mas o verdadeiro ganho é quando o tipo não importa. Se você estiver fazendo coisas como var customers = whatever; var query = from c in customers select stuffessa, não importa qual seja o tipo exato de 'cliente'. É óbvio como você pode usá-lo, e isso é suficiente. E se o tipo real é complicado, vale a pena suprimi-lo.
Joren
2
@ Kristoffer: Eu posso entender que querer eliminar a bagunça das tags, mas envolvê-las em uma classe não é (IMO) uma alternativa aceitável, pois você elimina a possibilidade de qualquer outra classe filho (legítima) desse tipo genérico. um parâmetro válido. Prefiro usar uma using ShortType = LongGenericType<A,B,C>diretiva na parte superior de um arquivo, pois isso fornece a mesma legibilidade, não requer que você recrie os construtores e não elimina as classes filhas de serem candidatas.
Adam Robinson
68

De Eric Lippert, engenheiro sênior de design de software da equipe de C #:

Por que a varpalavra - chave foi introduzida?

Existem duas razões, uma que existe hoje, uma que aparecerá na versão 3.0.

A primeira razão é que esse código é incrivelmente feio por causa de toda a redundância:

Dictionary<string, List<int>> mylists = new Dictionary<string, List<int>>();

E esse é um exemplo simples - escrevi pior. Sempre que você é forçado a digitar exatamente a mesma coisa duas vezes, é uma redundância que podemos remover. Muito melhor escrever

var mylists = new Dictionary<string,List<int>>();

e deixe o compilador descobrir qual é o tipo com base na atribuição.

Segundo, o C # 3.0 apresenta tipos anônimos. Como os tipos anônimos, por definição, não têm nomes, é necessário deduzir o tipo da variável a partir da expressão inicial, se o tipo for anônimo.

Ênfase minha. O artigo inteiro, C # 3.0, ainda é estaticamente digitado, honesto! e as séries seguintes são muito boas.

É para isso que varserve. Outros usos provavelmente não funcionarão tão bem. Qualquer comparação com JScript, VBScript ou digitação dinâmica é total. Observe novamente, varé necessário para que outros recursos funcionem no .NET.

Dustman
fonte
Acho o argumento de Lippert estranho. Ninguém digita o nome da segunda classe, eles permitem que o Intellisense escreva para eles, mas ele se vira e afirma que var é melhor porque o compilador / Intellisense resolve isso. Você não pode ter os dois lados!
21710 Dave
5
A equipe de C # não controla o intellisense, eles controlam o compilador. De qualquer forma, essa não é a questão principal. Eu não acho que var teria feito os 100 pontos em salvar digitação sozinho.
Dustman
@ Dustman: var não economiza digitação. Faz você escrever mais!
Piotr Perak #
53

Eu acho que o uso de var deve ser associado a nomes de variáveis ​​escolhidos com sabedoria.

Não tenho nenhum problema em usar var em uma instrução foreach, desde que não seja assim:

foreach (var c in list) { ... }

Se fosse mais assim:

foreach (var customer in list) { ... }

... então alguém lendo o código teria muito mais chances de entender o que é "lista". Se você tem controle sobre o nome da variável da lista, é ainda melhor.

O mesmo pode se aplicar a outras situações. Isso é bastante inútil:

var x = SaveFoo(foo);

... mas isso faz sentido:

var saveSucceeded = SaveFoo(foo);

Cada um na sua, eu acho. Eu me vi fazendo isso, o que é insano:

var f = (float)3;

Preciso de algum tipo de programa var de 12 etapas. Meu nome é Matt e eu (ab) uso var.

Matt Hamilton
fonte
6
Bem, a única coisa errada com "var f = (float) 3;" é que ele deve ser "var f = 3f" ou "var f = 3.0 (causar precisão única é uma porcaria)".
MichaelGG
3
Heh yeah 3f ou 3.0 é o caminho a seguir! Nós, maníacos, temos que ficar juntos!
Matt Hamilton
27
O verdadeiro problema nesse primeiro exemplo é "lista", não "c". "lista" de quê ? "list" deve ser renomeado para "customers" ou "customersWhoOweMoney" ou "currentCustomers" ou algo muito mais descritivo. E uma vez que você tenha isso, o "c" pode permanecer como está, porque você já sabe o que ele conterá.
Ryan Lundy
4
Oi Matt! Meu nome é Kenny e sou um viciado em drogas.
Kenny
var MattHamil = "Luke Skywalker"; // tirou uma tonelada dela
Binoj Antony
40

Adotamos o código de ética "Código para pessoas, não para máquinas", com base no pressuposto de que você passa várias vezes mais tempo no modo de manutenção do que no novo desenvolvimento.

Para mim, isso exclui o argumento de que o compilador "sabe" que tipo é a variável - com certeza, você não pode escrever um código inválido pela primeira vez porque o compilador interrompe a compilação do código, mas quando o próximo desenvolvedor estiver lendo o código dentro de seis meses, eles precisam deduzir o que a variável está fazendo de maneira correta ou incorreta e identificar rapidamente a causa dos problemas.

Portanto,

var something = SomeMethod();

é proibido pelos nossos padrões de codificação, mas o seguinte é incentivado em nossa equipe porque aumenta a legibilidade:

var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
   DoWork( item ); 
}
Dexter
fonte
4
Descobri que ("Código para pessoas, não para máquinas") é uma excelente diretriz - segui-lo pode resultar em um código melhor e ajuda a evitar a otimização prematura.
Thanatos 28/05
3
Eu não recebo var list = new KeyValuePair <string, double>? Para mim, uma lista pode ter mais do que isso.
TTT
"Código para pessoas, não para máquinas" - amém.
user1068352
39

Não é ruim, é mais uma coisa estilística, que tende a ser subjetiva. Pode adicionar inconsistências, quando você usa var e quando não.

Outro caso de preocupação, na chamada a seguir, você não pode dizer apenas olhando para o código do tipo retornado por CallMe:

var variable = CallMe();

Essa é a minha principal reclamação contra var.

Uso var quando declaro delegados anônimos nos métodos, de alguma forma var parece mais limpo do que se eu usasse Func. Considere este código:

var callback = new Func<IntPtr, bool>(delegate(IntPtr hWnd) {
   ...
});

EDIT : Atualizado o último exemplo de código com base na entrada de Julian

Ion Todirel
fonte
3
Mas você realmente precisa saber o tipo ali nessa linha? Você sabe que o CallMe retorna algo; não basta saber que uma variável local chamada variableé criada? A menos que você expanda seu exemplo, essa não é uma reclamação muito sólida, IMO.
Randolpho
2
Não se trata de não ser detalhado, é de não deixar que o compilador faça o açúcar da sintaxe para você. Considere o seguinte: var getter ..., agora esse Func <object> getter ..., com o segundo você sabe que não precisa fornecer nenhum parâmetro e o que ele retorna. Você sabe desde o início "o que fazer" e pode tomar decisões mais rapidamente ao projetar algo ou refatorar. Ter todas as informações em mãos é mais importante do que mais alguns caracteres. Isso só pode ser apreciado quando você estiver trabalhando com muito código.
Ion Todirel
2
Como todos nós estamos falando sobre o visual studio de qualquer maneira, qual é o problema de passar o mouse sobre a variável por um segundo e apenas ver que tipo é? Muito melhor do que correr para a declaração de qualquer maneira.
Rubys
3
Os nomes genéricos de variáveis ​​e funções ( variable, CallMe) são maus exemplos. No entanto, se CallMe()fosse uma função em algum tipo de "aplicativo de telefone", var call = CallMe(); .... call.HangUp();faria muito mais sentido.
Danko Durbić
3
@Randolpho: "qual é o problema de passar o mouse sobre a variável por um segundo e ver que tipo é essa?" Isso adiciona tempo à sobrecarga de manutenção ... mais um segundo é apenas o tempo de foco em vez de contar o teclado para a alternância de contexto do mouse. Não sei você, mas trabalho com prazo. Toda vez que preciso passar o mouse sobre uma variável para descobrir que tipo é, é hora de gastar mais tempo corrigindo um problema.
Powerlord 19/05/10
36

Var não é como uma variante. A variável ainda é fortemente digitada, mas você não pressiona as teclas para obtê-la dessa maneira. Você pode passar o mouse sobre ele no Visual Studio para ver o tipo. Se você estiver lendo um código impresso, é possível que pense um pouco para descobrir qual é o tipo. Mas há apenas uma linha que a declara e muitas linhas que a utilizam, portanto, dar nomes decentes às coisas ainda é a melhor maneira de facilitar o seu código.

O uso do Intellisense é preguiçoso? É menos digitado que o nome inteiro. Ou há coisas que são menos trabalhosas, mas não merecem críticas? Eu acho que existem, e var é um deles.

Kate Gregory
fonte
6
+1, única pessoa a observar que varnão tem nada a ver Variant.
User7116
27

O momento mais provável em que você precisará disso é para tipos anônimos (onde é 100% necessário); mas também evita repetições nos casos triviais, e a IMO torna a linha mais clara. Não preciso ver o tipo duas vezes para uma inicialização simples.

Por exemplo:

Dictionary<string, List<SomeComplexType<int>>> data = new Dictionary<string, List<SomeComplexType<int>>>();

(por favor, não edite o hscroll acima - isso meio que prova o ponto !!!)

vs:

var data = new Dictionary<string, List<SomeComplexType<int>>>();

No entanto, há ocasiões em que isso é enganoso e pode causar bugs. Tenha cuidado ao usar varse a variável original e o tipo inicializado não forem idênticos. Por exemplo:

static void DoSomething(IFoo foo) {Console.WriteLine("working happily") }
static void DoSomething(Foo foo) {Console.WriteLine("formatting hard disk...");}

// this working code...
IFoo oldCode = new Foo();
DoSomething(oldCode);
// ...is **very** different to this code
var newCode = new Foo();
DoSomething(newCode);
Marc Gravell
fonte
1
(para informações, você pode obter problemas semelhantes em qualquer coisa em que esta é uma conversão implícita de tipo)
Marc Gravell
1
Não concorde com a parte que você não deseja vê-la duas vezes na mesma linha. É possível que, no futuro, você não esteja criando diretamente a variável depois de declarar (por exemplo, se estiver abaixo da definição), talvez não fique claro diretamente qual é o tipo. A maioria dos desenvolvedores é usada para ver o tipo diretamente no início da linha, especialmente em códigos complexos que você não deseja dificultar a leitura do código.
Gertjan
@TheVillageIdiot - revirei sua edição, porque nessa ocasião o hscroll está relacionado ao ponto ;-p
Marc Gravell
2
@Gertjan - meu cérebro é limitado; se for complexo, não quero vê-lo duas vezes e tenho que começar a comparar (interface / concreto / etc). Fico feliz em vê-lo uma vez e pensar "digitado como um deles".
Marc Gravell
17

Um caso específico em que var é difícil: revisões de código offline, especialmente as feitas no papel.

Você não pode confiar em passar o mouse para isso.

Jon Limjap
fonte
17
Por que diabos você está revisando o código no papel? Pense nas árvores! ;)
Dustman
8
Você pode ter o mesmo problema sem usar var. O problema não é var; o problema são nomes de variáveis ​​incorretos. Se nomes de variáveis ​​são bem escolhidos, o uso de var não importa.
22611 Ryan Lundy
Eu tenho um cara na minha equipe que analisa seu próprio código e procura bugs, imprimindo seu código. Suas paredes estão cobertas de código. Uma vez entrei e ele tinha um quadro branco grande inteiro coberto com um único de seus exercícios de depuração. Foi provavelmente ~ 10000 LOC
Beep beep
Somente nomes de variáveis ​​não resolvem o problema, a menos que você volte à notação húngara, na qual o tipo faz parte do nome.
Kevin Gale
17

Não vejo qual é o grande problema ..

var something = someMethod(); // Type of 'something' not clear <-- not to the compiler!

Você ainda tem total conhecimento de algo e, para qualquer caso ambíguo, você tem seus testes de unidade, certo? ( você? )

Não é varchar, não é sombrio e certamente não é uma digitação dinâmica ou fraca. Está parando maddnes assim:

List<somethinglongtypename> v = new List<somethinglongtypename>();

e reduzindo a desordem total para:

var v = new List<somethinglongtypename>();

Bom, não tão bom quanto:

v = List<somethinglongtypename>();

Mas então é para isso que serve o Boo .

Frep D-Oronge
fonte
o tipo de 'algo' é muito claro para o compilador; internamente, o "var" é definido como o tipo de retorno de 'someMethod', é claro para o compilador, mas pode não ser claro para os desenvolvedores que trabalham no projeto. e Boo está crescendo em mim rapidamente.
stephenbayer
Não, v = List<somethinglongtypename>();não é nem melhor. É importante distinguir entre a introdução de uma nova variável e a atribuição a uma variável existente.
HighCommander4
Bem, se você atribuiu a 'v' antes no escopo atual, é uma atribuição a uma existente. Caso contrário, é atribuída à nova variável 'v'. Fácil.
Frep D-Oronge
17

Se alguém está usando a varpalavra - chave porque não deseja "descobrir o tipo", esse é definitivamente o motivo errado. A varpalavra-chave não cria uma variável com um tipo dinâmico, o compilador ainda precisa saber o tipo. Como a variável sempre tem um tipo específico, o tipo também deve ser evidente no código, se possível.

Boas razões para usar a varpalavra - chave são, por exemplo:

  • Onde é necessário, ou seja, declarar uma referência para um tipo anônimo.
  • Onde torna o código mais legível, ou seja, removendo declarações repetitivas.

Escrever o tipo de dados geralmente torna o código mais fácil de seguir. Ele mostra quais tipos de dados você está usando, para que você não precise descobrir o tipo de dados, primeiro descobrindo o que o código faz.

Guffa
fonte
11

Dado o quão poderoso o Intellisense é agora, não tenho certeza de que var seja mais difícil de ler do que ter variáveis-membro em uma classe ou variáveis ​​locais em um método definido na área visível da tela.

Se você tiver uma linha de código como

IDictionary<BigClassName, SomeOtherBigClassName> nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();

É muito mais fácil ou difícil de ler do que:

var nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();
Colin Desmond
fonte
Na verdade, eu não considerei isso, pelo que parece da outra pergunta, que é um ponto bastante forte para outro momento de usá-lo.
Finglas
Que era basicamente a única razão que implementou (além de ser capaz de declarar tipos anônimos, mas eles poderiam ter feito "var" uma palavra-chave especial que era apenas para tipos anônimos.)
MQP
10

Eu acho que o principal com o VAR é usá-lo apenas quando apropriado, ou seja, ao fazer coisas no Linq que ele facilita (e provavelmente em outros casos).

Se você tem um tipo para algo, deve usá-lo - não fazer isso é preguiça simples (em oposição à preguiça criativa, que geralmente deve ser incentivada) - bons programadores costumam trabalhar muito duro para serem preguiçosos e podem ser considerados a fonte da coisa em primeiro lugar).

Uma proibição geral é tão ruim quanto abusar da construção em primeiro lugar, mas é necessário que haja um padrão de codificação sensato.

A outra coisa a lembrar é que não é um tipo de VB var, pois não pode alterar tipos - é uma variável fortemente tipada, apenas que o tipo é inferido (e é por isso que existem pessoas que argumentam que não é razoável use-o, digamos, em um foreach, mas eu discordaria por razões de legibilidade e manutenção).

Eu suspeito que este vai rodar e rodar (-:

Murph

Murph
fonte
10

Claro, inté fácil, mas quando o tipo da variável é IEnumerable<MyStupidLongNamedGenericClass<int, string>>, var torna as coisas muito mais fáceis.

Blorgbeard está fora
fonte
2
+1 para isso. intversus varé algo para se discutir, mas vários tipos genéricos aninhados são varuma dádiva de Deus. É aqui que o uso repetido do nome do tipo realmente destrói a legibilidade do código.
Chris Farmer
Esta é absolutamente a razão errada para usá-lo. Se o seu código usa um tipo genérico aninhado, você deve derivar uma classe nomeada específica para ele. Por exemplo: class IntStringEnumerator : IEnumerable<MyStupidLongNamedGenericClass<int, string>>e use o novo nome. Isso limpa o código e descreve melhor o tipo.
Xxbbcc
Tudo bem, mas meu exemplo foi apenas hipérbole. IntStringEnumerator i = new IntStringEnumerator()ainda está digitando demais.
Blorgbeard sai
9

Roubado do post sobre esta questão no CodingHorror :


Infelizmente, você e todos os demais entenderam errado. Embora eu concorde com você que a redundância não é uma coisa boa, a melhor maneira de resolver esse problema seria fazer algo como o seguinte:

MyObject m = novo ();

Ou se você estiver passando parâmetros:

Pessoa p = novo ("Nome", "Sobrenome);

Onde na criação de um novo objeto, o compilador deduz o tipo do lado esquerdo, e não do lado direito. Isso tem outras vantagens sobre o "var", pois também pode ser usado em declarações de campo (também existem outras áreas que podem ser úteis, mas não vou entrar aqui).

No final, simplesmente não pretendia reduzir a redundância. Não me interpretem mal, "var" é MUITO importante em C # para tipos / projeções anônimas, mas o uso aqui é MUITO FORA (e eu venho dizendo isso há muito, muito tempo) à medida que você ofusca o tipo que está sendo usado. Ter que digitá-lo duas vezes é muito frequente, mas declarar zero vezes é muito pouco.

Nicholas Paldino .NET / C # MVP em 20 de junho de 2008 08:00


Eu acho que se sua principal preocupação é digitar menos - então não há nenhum argumento que o impeça de usá-lo.

Se você está indo só para nunca ser a pessoa que olha para o seu código, então quem se importa? Caso contrário, em um caso como este:

var people = Managers.People

está tudo bem, mas em um caso como este:

var fc = Factory.Run();

provoca um curto-circuito em qualquer dedução imediata de tipo que meu cérebro possa começar a formar a partir do 'inglês' do código.

Caso contrário, use seu melhor julgamento e programação 'cortesia' para com outras pessoas que possam ter que trabalhar em seu projeto.

Rostov
fonte
4
Seus exemplos acima não são argumentos para não usar var; eles são um argumento para usar bons nomes de variáveis ​​descritivos. Se, em vez de [var fc = Factory.Run ();] você tivesse [bool fc = Factory.Run ();], o código não se tornaria mais claro.
21719 Ryan Lundy
9

O uso em varvez do tipo explícito facilita muito as refatorações (portanto, devo contradizer os pôsteres anteriores que queriam dizer que não faziam diferença ou que era puramente "açúcar sintático").

Você pode alterar o tipo de retorno dos seus métodos sem alterar todos os arquivos nos quais esse método é chamado. Imagine

...
List<MyClass> SomeMethod() { ... }
...

que é usado como

...
IList<MyClass> list = obj.SomeMethod();
foreach (MyClass c in list)
  System.Console.WriteLine(c.ToString());
...

Se você quisesse refatorar SomeMethod()para retornar um IEnumerable<MySecondClass>, seria necessário alterar a declaração da variável (também dentro do foreach) em todos os lugares em que você usou o método.

Se você escrever

...
var list = obj.SomeMethod();
foreach (var element in list)
  System.Console.WriteLine(element.ToString());
...

em vez disso, você não precisa alterá-lo.

MartinStettner
fonte
concordou - imaginando por que esse belo efeito colateral não está sendo apresentado tanto quanto alguns dos outros profissionais mais subjetivos nas respostas mais populares.
fieldingmellish
Hoje aconteceu comigo. Eu tenho uma classe de fábrica que retorna istance de uma classe MainMenu. Hoje eu criei um MainMenu2 com a mesma interface do MainMenu. Eu tenho todo o meu código de aplicativo intocado após a alteração!
Marco Staffoli 9/11
8

@aku: Um exemplo são as revisões de código. Outro exemplo são os cenários de refatoração.

Basicamente, não quero caçar tipos com o mouse. Pode não estar disponível.

erlando
fonte
2
É interessante você dizer isso porque var pode simplificar a refatoração. Se você usou var, não precisa. Agora você pode sempre contar com ferramentas de refatoração do IDE, mas você sabe, você sempre pode contar com o IDE para o tipo de bem :)
Fred
8

É uma questão de gosto. Todo esse barulho sobre o tipo de uma variável desaparece quando você se acostuma a linguagens digitadas dinamicamente. Ou seja, se você começar a gostar deles (não tenho certeza se todos podem, mas eu gosto).

C # varé muito legal, pois parece uma digitação dinâmica, mas na verdade é estática - o compilador aplica o uso correto.

O tipo da sua variável não é realmente tão importante (isso já foi dito antes). Deve ser relativamente claro a partir do contexto (suas interações com outras variáveis ​​e métodos) e seu nome - não espere que customerList contenha um int...

Ainda estou esperando para ver o que meu chefe pensa sobre esse assunto - recebi um cobertor "vá em frente" para usar novas construções na versão 3.5, mas o que faremos com a manutenção?

Daren Thomas
fonte
7

Na sua comparação entre IEnumerable<int>e IEnumerable<double>você não precisa se preocupar - se você passar o tipo errado, seu código não será compilado de qualquer maneira.

Não há preocupação com a segurança de tipo, pois ela nãovar é dinâmica. É apenas mágica do compilador e qualquer tipo de chamada não segura que você fizer será capturado.

Var é absolutamente necessário para o Linq:

var anonEnumeration =
    from post in AllPosts()
    where post.Date > oldDate
    let author = GetAuthor( post.AuthorId )
    select new { 
        PostName = post.Name, 
        post.Date, 
        AuthorName = author.Name
    };

Agora olhe para anonEnumeration no intellisense e parecerá algo comoIEnumerable<'a>

foreach( var item in anonEnumeration ) 
{
    //VS knows the type
    item.PostName; //you'll get intellisense here

    //you still have type safety
    item.ItemId;   //will throw a compiler exception
}

O compilador C # é bastante inteligente - os tipos gerados separadamente terão o mesmo tipo gerado se suas propriedades corresponderem.

Fora isso, desde que você tenha inteligência, faz sentido usar em varqualquer lugar em que o contexto seja claro.

//less typing, this is good
var myList = new List<UnreasonablyLongClassName>();

//also good - I can't be mistaken on type
var anotherList = GetAllOfSomeItem();

//but not here - probably best to leave single value types declared
var decimalNum = 123.456m;
Keith
fonte
Por favor, remova-o IQueriable<T>antes de iterar: anonEnumeration.ToList();
David Diez 14/01
@DavidDiez você poderia reformular? Sua afirmação não faz sentido. Nenhum dos meus trechos de código faz referência IQueryableou.ToList()
Keith
var anonEnumeration = from post in AllPosts() where post.Date > oldDate let author = GetAuthor( post.AuthorId ) select new { PostName = post.Name, post.Date, AuthorName = author.Name };não retorna um IQueriable<T>?
David Diez
1
@DavidDiez depende do que AllPosts()retorna - o autor da pergunta se refere, List<T>então eu assumi isso. Nesse caso, o resultado é que anonEnumerationserá do tipo IEnumerable<'a>. Agora, se AllPosts()retorna, IQueryable<T>em seguida, anonEnumerationse tornará IQueryable<'a>(note ino Queryable) - no entanto, nesse caso, meu código ainda funciona porque IQueryable<T>implementa IEnumerable<T>. Existem muitas perguntas e respostas melhores aqui sobre as distinções entre eles - aqui meu caso 'aé anônimo e varpermite atribuí-lo a uma variável de tipo estaticamente.
Keith
Ohh, obrigado por explicá-lo :) Meu comentário foi porque iterar um IQueryable<T>não é uma boa prática, pois em cada iteração você está fazendo uma declaração de leitura no DB. Certifique-se *.ToList() IQueryable<T>é antes de iteração los
David Diez
7

Eu acho que depende da sua perspectiva. Pessoalmente, nunca tive dificuldade em entender um pedaço de código por causa de var"uso indevido", e meus colegas e eu o usamos bastante por todo o lado. (Concordo que o Intellisense é uma grande ajuda nesse sentido.) Congratulo-me com isso como uma maneira de remover detritos repetitivos.

Afinal, se declarações como

var index = 5; // this is supposed to be bad

var firstEligibleObject = FetchSomething(); // oh no what type is it
                                            // i am going to die if i don't know

eram realmente impossíveis de lidar, ninguém usaria linguagens dinamicamente tipadas.

mqp
fonte
Presumivelmente no .Net 4, onde tipos dinâmicos são lugares comuns, isso se tornará mais importante?
Colin Desmond
2
Pelo contrário, se você está confuso com "var" agora, eu esperaria que você também ficasse confuso com "dinâmico". Deus não permita que alguém já declara uma dinâmica e, em seguida, faz uma referência a ele usando o "var" :)
MQP
Eu quis dizer algo como dinâmico d = 52; var x = d; o que deveria estar bem.
Mqp 7/08/09
7

Eu só uso var quando está claro para ver que tipo é usado.

Por exemplo, eu usaria var neste caso, porque você pode ver imediatamente que x será do tipo "MyClass":

var x = new MyClass();

Eu NÃO usaria var em casos como este, porque você precisa arrastar o mouse sobre o código e olhar a dica de ferramenta para ver qual tipo MyFunction retorna:

var x = MyClass.MyFunction();

Especialmente, nunca uso var nos casos em que o lado direito nem sequer é um método, mas apenas um valor:

var x = 5;

(porque o compilador não pode saber se eu quero um byte, curto, int ou o que for)

Christian Specht
fonte
Se o lado direito não é suficientemente claro para justificar o uso var, então varnão é o problema: o lado direito é o problema. Não é suficientemente descritivo . Customer c = GetContext()é ainda pouco clara e não é melhor do que usar var.
perfil completo de JulianR
6

Para mim, a antipatia para varilustra por que o bilinguismo no .NET é importante. Para os programadores de C # que também fizeram o VB .NET, as vantagens de varsão intuitivamente óbvias. A declaração C # padrão de:

List<string> whatever = new List<string>();

é o equivalente, no VB .NET, de digitar isso:

Dim whatever As List(Of String) = New List(Of String)

Ninguém faz isso no VB .NET, no entanto. Seria bobagem, porque desde a primeira versão do .NET você foi capaz de fazer isso ...

Dim whatever As New List(Of String)

... que cria a variável e inicializa tudo em uma linha razoavelmente compacta. Ah, mas e se você quiser um IList<string>, não um List<string>? Bem, no VB .NET, isso significa que você precisa fazer isso:

Dim whatever As IList(Of String) = New List(Of String)

Assim como você faria em C #, e obviamente não poderia usar varpara:

IList<string> whatever = new List<string>();

Se você precisar que o tipo seja algo diferente, pode ser. Mas um dos princípios básicos de uma boa programação é reduzir a redundância, e é exatamente isso que o var faz.

Ryan Lundy
fonte
1
Engraçado você mencionar o bilinguismo como algo que promove o uso de var. Meu antagonismo em relação à palavra-chave var decorre diretamente da minha fluência em javascript! :)
urig
varem C # não tem nenhuma conexão com varJavaScript. Uma varvariável declarada em C # é fortemente tipada.
Ryan Lundy
6

Use-o para tipos anônimos - é para isso que serve. Qualquer outra coisa é um uso longe demais. Como muitas pessoas que cresceram em C, estou acostumado a olhar para o lado esquerdo da declaração para o tipo. Não olho para o lado direito, a menos que precise. Usar varqualquer declaração antiga me faz fazer isso o tempo todo, o que eu pessoalmente acho desconfortável.

Aqueles que dizem 'não importa, use o que você gosta' não estão vendo a imagem toda. Todo mundo pega o código de outras pessoas em um ponto ou outro e precisa lidar com as decisões que tomou no momento em que o escreveu. É ruim o suficiente ter que lidar com convenções de nomes radicalmente diferentes ou - os estilos clássicos de fixação, sem adicionar a coisa toda ' varou não' à mistura. O pior caso é quando um programador não usou vare, em seguida, vem um mantenedor que o ama e estende o código usando-o. Então agora você tem uma bagunça profana.

Os padrões são uma coisa boa, precisamente porque eles significam que você tem muito mais chances de conseguir código aleatório e de entender rapidamente. Quanto mais coisas diferentes, mais difícil fica. E mudar para o estilo 'var em qualquer lugar' faz uma grande diferença.

Não me importo com digitação dinâmica e não me importo com digitação implícita - em idiomas projetados para eles. Eu gosto bastante de Python. Mas o C # foi projetado como uma linguagem estaticamente explícita e é assim que deve permanecer. Quebrar as regras para tipos anônimos já era ruim; deixar as pessoas levar isso ainda mais longe e quebrar ainda mais os idiomas da língua é algo com o qual não estou feliz. Agora que o gênio está fora da garrafa, ele nunca mais voltará. O C # ficará balcanizado em campos. Não é bom.

Neil Hewitt
fonte
7
Uau. Ignorar todos os argumentos apresentados neste tópico até agora e redefinir toda a discussão é uma conquista.
Konrad Rudolph
Esse 100% descreve como me sinto em relação a 'var', particularmente do ponto de vista de pegar o código de outra pessoa. O uso de var altera radicalmente a tarefa em questão, se estiver cheia. +1
Simon
6

Muitas vezes durante o teste, eu me vejo tendo um código como este:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();
Console.WriteLine(something);

Agora, às vezes, quero ver o que o SomeOtherThing em si contém. SomeOtherThing não é o mesmo tipo que CallMethod () retorna. Já que estou usando var, apenas mudo isso:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();

para isso:

var something = myObject.SomeProperty.SomeOtherThing;

Sem var, eu teria que continuar alterando o tipo declarado também no lado esquerdo. Eu sei que é menor, mas é extremamente conveniente.

BFree
fonte
6

Para os aficionados que pensam que vareconomizam tempo, são necessárias menos teclas digitadas:

StringBuilder sb = new StringBuilder();

do que

var sb = new StringBuilder();

Conte-os se você não acredita em mim ...

19 versus 21

Vou explicar se for preciso, mas tente ... (dependendo do estado atual do seu intelecto, talvez seja necessário digitar mais alguns para cada um)

E é verdade para todos os tipos que você pode imaginar !!

Meu sentimento pessoal é que var nunca deve ser usado, exceto onde o tipo não é conhecido porque reduz a legibilidade do reconhecimento no código. O cérebro leva mais tempo para reconhecer o tipo do que uma linha completa. Os veteranos que entendem código de máquina e bits sabem exatamente do que estou falando. O cérebro processa em paralelo e, quando você usa var, força-o a serializar sua entrada. Por que alguém iria querer fazer seu cérebro trabalhar mais? É para isso que servem os computadores.

Wray Smallwood
fonte
Acho a repetição de stringBuilder sb = new StringBuilder () bagunçada e mais demorada para reconhecer claramente. É barulho extra. O problema é que determinar o que faz e o que não constitui um esforço intelectual extra para entender algum código é bastante subjetivo!
Ljs
"var nunca deve ser usado, exceto onde o tipo não é conhecido ..." - SEMPRE você pode conhecer o tipo, assim como o compilador. Isso não é digitação dinâmica, apenas permite que o compilador determine o tipo para você. Mas o tipo nunca é um desconhecido.
Gabriel Magana
5

I divisão var todo os lugares, os lugares só questionáveis para mim são tipos de curto internos, por exemplo, eu prefiro int i = 3;maisvar i = 3;

robi-y
fonte
5

Certamente isso pode simplificar as coisas, a partir do código que escrevi ontem:

var content  = new Queue<Pair<Regex, Func<string, bool>>>();
...
foreach (var entry in content) { ... }

Isso seria extremamente detalhado sem var.

Adendo: Um pouco de tempo gasto com uma linguagem com inferência de tipo real (por exemplo, F #) mostrará o quão bons são os compiladores em obter o tipo de expressões correto. Certamente, isso significa que tenho a tendência de usar varo máximo possível e o uso de um tipo explícito agora indica que a variável não é do tipo da expressão de inicialização.

Richard
fonte
Sim, os compiladores são mais inteligentes que nós, supere isso!
10119 Benjol