Uso della parola chiave var in C #


406

Dopo una discussione con i colleghi sull'uso della parola chiave "var" in C # 3, mi chiedevo quali fossero le opinioni delle persone sugli usi appropriati dell'inferenza di tipo via var?

Ad esempio, ho usato pigramente var in circostanze discutibili, ad esempio: -

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.

Gli usi più legittimi di var sono i seguenti: -

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

È interessante notare che LINQ sembra essere un po 'di un'area grigia, ad esempio: -

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

È chiaro quali saranno i risultati nel fatto che sarà un tipo che implementa IEnumerable, tuttavia non è del tutto ovvio allo stesso modo di una var che dichiara un nuovo oggetto.

È ancora peggio quando si tratta di LINQ per gli oggetti, ad esempio: -

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

Questo non è migliore dell'equivalente foreach (elemento var in someList) {// ...} equivalente.

C'è una vera preoccupazione per la sicurezza dei tipi qui - per esempio se dovessimo inserire i risultati di quella query in un metodo sovraccarico che accettasse IEnumerable <int> e IEnumerable <double> il chiamante potrebbe inavvertitamente passare nel tipo sbagliato.

var non mantenere la tipizzazione forte, ma la domanda è se è pericoloso per il tipo di non essere immediatamente evidente sulla definizione, qualcosa che viene amplificato quando sovraccarichi errori medi compilatore potrebbero non essere emessi quando si passa involontariamente il tipo sbagliato di un metodo.


68
Usare var va bene, ma "Non devo capire il tipo" sembra una pessima ragione per usarlo ... dovresti sapere qual è il tipo, var è solo una scorciatoia per evitare di digitarlo
Thomas Levesque,

53
var i = 0;== fallito! var c = new CrazyFrigginLongClassName();== vinci!
dotjoe,

6
"Var mi ricorda anche il tipo di variante VB / VBA. Aveva anche il suo posto. Ricordo (da molti anni fa) che il suo utilizzo era un tipo tutt'altro che desiderabile ed era piuttosto affamato di risorse." <- mostra che questa è una domanda di innesco poiché il tipo 'var' di C # non ha nulla a che fare con il tipo di variante VB / VBA.
user7116,

20
var readabilityBeDamned = true;
spoulson,

9
Il problema con tutti gli esempi qui riportati è che stiamo esaminando UNA riga di codice. Quando vedo riga dopo riga di dichiarazioni "var", una dopo l'altra, mi sfugge di mano. La leggibilità è soggettiva, ma trovo che l'abuso sia molto più che usato rispettabilmente.
jro,

Risposte:


293

Penso ancora che varpossa rendere il codice più leggibile in alcuni casi. Se ho una classe Customer con una proprietà Orders e desidero assegnarla a una variabile, farò solo questo:

var orders = cust.Orders;

Non mi importa se Customer.Orders è IEnumerable<Order>, ObservableCollection<Order>o BindingList<Order>- tutto ciò che voglio è mantenere quell'elenco in memoria per scorrere su di esso o ottenere il suo conteggio o qualcosa in seguito.

Contrasta la dichiarazione sopra con:

ObservableCollection<Order> orders = cust.Orders;

Per me, il nome del tipo è solo rumore. E se torno indietro e decido di cambiare il tipo di Cliente.Ordini lungo il percorso (diciamo da ObservableCollection<Order>a IList<Order>), allora ho bisogno di cambiare anche quella dichiarazione - qualcosa che non avrei dovuto fare se avessi usato var nel primo posto.


48
Mi piace avere il tipo esplicito davanti a me quando leggo il codice. Come faccio a sapere cosa "cust.Orders" è qui senza il tipo? Sì, potrei passare il mouse sopra per scoprirlo, ma perché dovrei? :)
Jon Tackabury,

77
Ma il punto è che in generale non importa. Fornito cust.Orders è qualcosa che puoi enumerare (ad esempio foreach over), quindi non importa che tipo sia. Il codice aggiuntivo ostacola la lettura dell'intento.
Matt Hamilton,

67
Ma se richiedi solo quella cust.Orders è "qualcosa che puoi enumerare", allora non dichiararla come IEnumerable <Order> rende tale requisito esplicito e chiaro? Dichiararlo come var significa che si perde effettivamente tale requisito.
GrahamS,

5
@jon e come farebbero gli ordini IEnumerbal = cust.Orders foreach (var order in order) fare la differenza? l'unica cosa che IEnumerable dice è che puoi metterlo in una foreach ma lo sapevi già dalla riga sottostante
Rune FS

18
"l'unica cosa che IEnumerable dice è che puoi metterlo in una foreach" - esprime anche l'intenzione che l' unica cosa che puoi fare è enumerare. L'uso di var dà accesso e intellisense ai membri pubblici del tipo di raccolta concreta.
Joe,

167

Uso varampiamente. È stato criticato il fatto che ciò riduca la leggibilità del codice, ma nessun argomento a sostegno di tale affermazione.

Certo, può significare che non è chiaro con quale tipo abbiamo a che fare. E allora? Questo è in realtà il punto di un design disaccoppiato. Quando hai a che fare con le interfacce, non sei assolutamente interessato al tipo di variabile. varprende questo molto di più, è vero, ma penso che l'argomento rimane la stessa da un punto di vista leggibilità: Il programmatore non dovrebbe in realtà essere interessato al tipo della variabile, ma piuttosto in quello che una variabile fa . Questo è il motivo per cui Microsoft chiama anche l'inferenza del tipo "digitazione anatra".

Quindi, cosa fa una variabile quando la dichiaro usando var? Facile, fa qualunque cosa IntelliSense mi dica di fare. Qualsiasi ragionamento su C # che ignora l'IDE non è all'altezza della realtà. In pratica, ogni codice C # è programmato in un IDE che supporta IntelliSense.

Se sto usando una varvariabile dichiarata e mi confondo a cosa serve la variabile, c'è qualcosa di fondamentalmente sbagliato nel mio codice. varnon è la causa, rende visibili solo i sintomi. Non dare la colpa al messaggero.

Ora, il team di C # ha rilasciato una linea guida per la codifica che afferma che vardovrebbe essere usato solo per catturare il risultato di un'istruzione LINQ che crea un tipo anonimo (perché qui non abbiamo una vera alternativa var). Bene, fanculo. Fintanto che il team di C # non mi darà una valida argomentazione per questa linea guida, la ignorerò perché, secondo la mia opinione professionale e personale, è pura pazzia. (Mi dispiace; non ho alcun link alla linea guida in questione.)

In realtà, ci sono alcune (superficialmente) buone spiegazioni sul perché non dovresti usare, varma credo ancora che siano in gran parte sbagliate. Prendi l'esempio della "ricercabilità": l'autore afferma che varrende difficile la ricerca dei luoghi in cui MyTypeviene utilizzato. Giusto. Anche le interfacce. In realtà, perché dovrei voler sapere dove viene usata la classe? Potrei essere più interessato a dove è istanziato e questo sarà ancora ricercabile perché da qualche parte deve essere invocato il suo costruttore (anche se questo è fatto indirettamente, il nome del tipo deve essere menzionato da qualche parte).


14
In qualsiasi IDE decente, non si utilizza una ricerca di testo per ottenere l'utilizzo della classe, si ottiene l'IDE per farlo in base al suo albero di analisi o comunque identifica i tipi di oggetti. Dal momento che stiamo parlando di tipizzazione statica, questo troverà tutto tranne i tipi anonimi.
Dustman,

6
Odierei ereditare 100k righe di fonte senza documentazione e uso liberale di var. Soprattutto se si combina var con nomi di variabili poco utili. Potrei vederlo utile quando si illustra un punto (o si tratta di tipi anonimi) ma nel codice di produzione?
Shea,

7
Arnshea: bene hai già indicato il vero problema lì: i nomi delle variabili inutili e la documentazione mancante . Non riesco davvero a vedere cosa varcontribuisce alla confusione. Certamente, ci possono essere casi in cui è importante enfatizzare il tipo / dimensione di una variabile (ad es. Operazioni di bit di basso livello). Va bene: nessuno ha mai affermato che vardovrebbe essere usato esclusivamente. La regola è semplice: se causa davvero confusione, non usarla.
Konrad Rudolph,

17
Ogni esempio contrario a var che ho visto presuppone che il programmatore utilizzerà nomi di variabili senza significato. Ma forse è per questo che var è meglio che specificare esplicitamente un tipo: costringe il programmatore a trovare buoni nomi di variabili.
Ryan Lundy,

16
Microsoft chiama anche l'inferenza del tipo "digitazione anatra". - lo fanno davvero? Sarei scioccato ...
Anton Tykhyy,

118

Var, a mio parere, in C # è una buona cosa tm . Qualsiasi variabile così digitata è ancora fortemente tipizzata, ma ottiene il suo tipo dal lato destro dell'assegnazione in cui è definita. Poiché le informazioni sul tipo sono disponibili sul lato destro, nella maggior parte dei casi è superfluo e eccessivamente dettagliato doverle inserire anche sul lato sinistro. Penso che ciò aumenti significativamente la leggibilità senza ridurre la sicurezza del tipo.

Dal mio punto di vista, l'uso di buone convenzioni di denominazione per variabili e metodi è più importante dal punto di vista della leggibilità rispetto alle informazioni esplicite sul tipo. Se ho bisogno delle informazioni sul tipo, posso sempre passare con il mouse sopra la variabile (in VS) e ottenerle. In genere, tuttavia, non dovrebbero essere necessarie al lettore informazioni esplicite sul tipo. Per lo sviluppatore, in VS ottieni ancora Intellisense, indipendentemente da come viene dichiarata la variabile. Detto questo, potrebbero esserci ancora casi in cui ha senso dichiarare esplicitamente il tipo - forse hai un metodo che restituisce a List<T>, ma vuoi trattarlo come unIEnumerable<T>nel tuo metodo. Per essere certi di utilizzare l'interfaccia, dichiarare la variabile del tipo di interfaccia può renderlo esplicito. O, forse, vuoi dichiarare una variabile senza un valore iniziale, perché ottiene immediatamente un valore basato su una condizione. In tal caso è necessario il tipo. Se le informazioni sul tipo sono utili o necessarie, vai avanti e usale. Sento, tuttavia, che in genere non è necessario e il codice è più facile da leggere senza di esso nella maggior parte dei casi.


3
Sono d'accordo nel complesso. Il punto chiave qui secondo me è essere certi che l'intenzione sia chiara. Se non è chiaro per la maggior parte degli sviluppatori del team, è dannoso, non utile. Detto questo, personalmente sono un GRANDE fan di questo, ma ho dovuto frenarmi un po 'quando altri sviluppatori nella mia squadra hanno avuto problemi a determinare il mio intento. Vai a capire.
Steve Brouillard,

3
Eh, trovo più facile da leggere quando il tipo è sulla sinistra. Usando ReSharper, non devo digitare nuovamente il tipo sulla destra, quindi non mi dà fastidio.
BlueRaja - Danny Pflughoeft,

1
@BlueRaja - Trovo che l'uso di buoni nomi di variabili di solito elimini la necessità di preoccuparsi comunque del tipo effettivo per la comprensione. Intellisense è ancora disponibile sulle variabili definite "var", quindi non ho bisogno di conoscere il tipo per scegliere un metodo / proprietà su di esso durante la codifica.
tvanfosson,

2
Non si tratta tanto di scrivere codice quanto di leggere il codice.
BlueRaja - Danny Pflughoeft,

1
Devo solo essere piuttosto spinto quindi, ho bisogno di un buon metodo e nomi di variabili e una comprensione dei tipi su cui si opera per essere in grado di comprendere correttamente il codice che sto leggendo. Penso che tu abbia ragione, anche se è sintomatico di problemi più grandi. Uno di fiducia. Per essere sicuro che il codice stia facendo quello che sembra stia facendo, devi essere sicuro dei tipi utilizzati.
AnthonyWJones,

91

Nessuno di questi è assolutamente vero; varpuò avere effetti sia positivi che negativi sulla leggibilità. A mio avviso, vardovrebbe essere utilizzato quando una delle seguenti condizioni è vera:

  1. Il tipo è anonimo (beh, qui non hai scelta, dato che in questo caso deve essere var)
  2. Il tipo è ovvio in base all'espressione assegnata (ovvero var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating())

varnon ha alcun impatto sulle prestazioni, in quanto è zucchero sintattico; il compilatore deduce il tipo e lo definisce una volta compilato in IL; non c'è nulla di veramente dinamico al riguardo.


1
sono d'accordo su entrambi, anche se ho lunghe restrizioni sul secondo caso, se un tipo è così lungo è di solito un tipo generico con molti argomenti generici nidificati, in tal caso un "ShortType equivalente fortemente tipizzato a TypeWithAReallyLongNameTheresNoSenseRepeating" ha più senso
Ion Todirel,

12
Non desidero iniziare una guerra religiosa, ma personalmente tendo a non essere d'accordo con Ion. Preferirei di gran lunga un nome di tipo molto lungo, ma molto preciso (ala zio Bob Martin) rispetto a un nome di tipo abbreviato e forse ambiguo più breve. Aggiungerò l'avvertenza che NON concordo nemmeno nel gonfiare artificialmente la lunghezza del nome. Se 5 personaggi creano un nome conciso che mostra chiaramente l'intento, usa 5 e non 25.
Steve Brouillard,

2
@Steve: devo essere d'accordo con te; la creazione di un "tipo breve" (che presumo tu intenda come ereditazione dal tipo generico specifico al solo scopo di abbreviare il nome) non è una buona pratica; richiederà di duplicare e passare attraverso qualsiasi costruttore dal tipo generico, oltre a impedirti di passare un tipo diverso che eredita dal tipo generico alla funzione. Stai usando l'eredità come typedefquando non lo è.
Adam Robinson,

7
Utilizzare varquando il tipo è ovvio? Forse, ma il vero guadagno è quando il tipo non ha importanza. Se stai facendo cose del genere var customers = whatever; var query = from c in customers select stuff, non importa quale sia il tipo esatto di "clienti". È ovvio come puoi usarlo, ed è abbastanza. E se il tipo reale è ingombrante, vale la pena sopprimerlo.
Joren,

2
@Kristoffer: Capisco il voler eliminare il disordine dei tag, ma avvolgerli in una classe non è (IMO) un'alternativa accettabile, dal momento che si taglia fuori la possibilità di qualsiasi altra classe figlio (legittima) di quel tipo generico dall'essere un parametro valido. Preferirei utilizzare una using ShortType = LongGenericType<A,B,C>direttiva nella parte superiore di un file, poiché offre la stessa leggibilità, non richiede di ricreare i costruttori e non elimina le classi figlio dall'essere candidati.
Adam Robinson,

68

Da Eric Lippert, Senior Software Design Engineer nel team C #:

Perché è stata varintrodotta la parola chiave?

Ci sono due motivi, uno che esiste oggi, uno che comparirà in 3.0.

Il primo motivo è che questo codice è incredibilmente brutto a causa di tutta la ridondanza:

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

E questo è un semplice esempio: ho scritto di peggio. Ogni volta che sei costretto a digitare esattamente la stessa cosa due volte, è una ridondanza che possiamo rimuovere. Molto più bello da scrivere

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

e lascia che il compilatore capisca quale tipo si basa sull'assegnazione.

In secondo luogo, C # 3.0 introduce tipi anonimi. Poiché i tipi anonimi per definizione non hanno nomi, è necessario poter inferire il tipo della variabile dall'espressione di inizializzazione se il suo tipo è anonimo.

Enfasi mia. L'intero articolo, C # 3.0 è ancora tipizzato staticamente, onesto! e le serie che ne conseguono sono piuttosto buone.

Questo è ciò che varserve. Altri usi probabilmente non funzioneranno così bene. Qualsiasi confronto con JScript, VBScript o tipizzazione dinamica è completamente a castello. Nota di nuovo, varè necessario per far funzionare determinate altre funzionalità in .NET.


Trovo strano l'argomento di Lippert. Nessuno digita il nome della seconda classe, lasciano che Intellisense lo scriva per loro, ma poi si gira e afferma che var è meglio perché il compilatore / Intellisense lo risolve. Non puoi averlo in entrambi i modi!
Dave,

5
Il team di C # non controlla l'intellisense, controlla il compilatore. In ogni caso non è questo il problema principale. Non credo che var avrebbe guadagnato i 100 punti solo salvando la digitazione.
Dustman,

@Dustman: var non salva affatto la digitazione. Ti fa scrivere di più!
Piotr Perak,

53

Penso che l'uso di var dovrebbe essere abbinato a nomi di variabili scelti con saggezza.

Non ho problemi a usare var in un'istruzione foreach, a condizione che non sia così:

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

Se fosse più così:

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

... allora qualcuno che legge il codice sarebbe molto più propenso a capire cosa sia "elenco". Se hai il controllo sul nome della variabile elenco stessa, è ancora meglio.

Lo stesso può valere per altre situazioni. Questo è abbastanza inutile:

var x = SaveFoo(foo);

... ma questo ha senso:

var saveSucceeded = SaveFoo(foo);

Ciascuno per conto suo, immagino. Mi sono trovato a fare questo, che è semplicemente folle:

var f = (float)3;

Ho bisogno di una sorta di programma var in 12 passaggi. Mi chiamo Matt e (ab) uso var.


6
Beh, l'unica cosa sbagliata con "var f = (float) 3;" è che dovrebbe essere "var f = 3f" o "var f = 3.0 (causa succhiature di precisione singole)".
MichaelGG,

3
Heh yeah 3f o 3.0 è la strada da percorrere! Noi var maniaci dobbiamo restare uniti!
Matt Hamilton,

27
Il vero problema in quel primo esempio è "list", non "c". "elenco" di cosa ? "list" dovrebbe essere rinominato in "clienti", o "customersWhoOweMoney", o "currentCustomers", o qualcosa di molto più descrittivo. E una volta che lo hai, la "c" può rimanere così com'è, perché sai già cosa conterrà.
Ryan Lundy,

4
Ciao Matt! Mi chiamo Kenny e sono un varaddict.
Kenny,

var MattHamil = "Luke Skywalker"; // ne ha tolto una tonnellata
Binoj Antony,

40

Abbiamo adottato l'ethos "Codice per le persone, non per le macchine", basato sul presupposto che si spenda più volte più a lungo in modalità di manutenzione rispetto al nuovo sviluppo.

Per me, questo esclude l'argomento secondo cui il compilatore "conosce" il tipo di variabile - certo, non puoi scrivere codice non valido la prima volta perché il compilatore interrompe la compilazione del codice, ma quando lo sviluppatore successivo sta leggendo il codice in 6 mesi devono essere in grado di dedurre ciò che la variabile sta facendo correttamente o in modo errato e identificare rapidamente la causa dei problemi.

Così,

var something = SomeMethod();

è vietato dai nostri standard di codifica, ma quanto segue è incoraggiato dal nostro team perché aumenta la leggibilità:

var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
   DoWork( item ); 
}

4
Ho scoperto che ("Codice per le persone, non per le macchine") è una linea guida eccellente: seguirlo può portare a un codice migliore e aiuta a evitare l'ottimizzazione prematura.
Thanatos,

3
Non ottengo var list = new KeyValuePair <string, double>? Per me un elenco può avere più che sulla cosa.
TTT

"Codice per le persone, non per le macchine" - amen.
user1068352

39

Non è male, è più una cosa stilistica, che tende ad essere soggettiva. Può aggiungere incoerenze, quando usi var e quando non lo fai.

Un altro caso di preoccupazione, nella seguente chiamata non si può dire semplicemente guardando il codice restituito dal tipo CallMe:

var variable = CallMe();

Questa è la mia lamentela principale contro la var.

Uso var quando dichiaro delegati anonimi nei metodi, in qualche modo var sembra più pulito che se usassi Func. Considera questo codice:

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

EDIT : aggiornato l'ultimo esempio di codice basato sull'input di Julian


3
Ma hai davvero bisogno di conoscere il tipo proprio lì su quella linea? Sai che CallMe restituisce qualcosa; non è sufficiente sapere che variableviene creata una variabile locale denominata ? A meno che non espandi il tuo esempio, questo non è un reclamo molto solido, IMO.
Randolpho,

2
Non si tratta di non essere prolisso, non di lasciare che il compilatore faccia lo zucchero della sintassi per te. Considera questo: var getter ..., ora questo Func <oggetto> getter ..., con il secondo che sai che non devi fornire alcun parametro e cosa restituisce. Sai fin dall'inizio "cosa fare" e puoi prendere decisioni più velocemente, quando progetti o rifatti. Avere tutte le informazioni a portata di mano è più importante di qualche altro personaggio. Questo può essere apprezzato solo quando lavori con un sacco di codice.
Ion Todirel,

2
Dal momento che stiamo tutti parlando di Visual Studio, qual è il grosso problema di passare il mouse sopra la variabile per un secondo e vedere solo di che tipo è? Molto meglio che correre alla dichiarazione comunque.
Rubys,

3
I nomi generici di variabili e funzioni ( variable, CallMe) sono un cattivo esempio. Tuttavia, se CallMe()fosse una funzione in una sorta di "applicazione telefonica", var call = CallMe(); .... call.HangUp();avrebbe molto più senso.
Danko Durbić,

3
@Randolpho: "Qual è il grosso problema di passare il mouse sopra la variabile per un secondo e vedere solo di che tipo è?" Aggiunge tempo al sovraccarico di manutenzione ... più un secondo è solo il tempo di passaggio del mouse anziché contare il cambio di contesto da tastiera a mouse. Non ti conosco, ma lavoro con una scadenza. Ogni volta che devo passare con il mouse su una variabile per scoprire che tipo è, è tempo che avrei potuto spendere meglio per risolvere un problema.
Powerlord,

36

Var non è affatto una variante. La variabile è ancora fortemente tipizzata, è solo che non premi i tasti per farlo in quel modo. Puoi passare con il mouse su di esso in Visual Studio per vedere il tipo. Se stai leggendo il codice stampato, è possibile che tu debba pensare un po 'per capire quale sia il tipo. Ma c'è solo una riga che lo dichiara e molte righe che lo usano, quindi dare cose decenti è ancora il modo migliore per rendere il tuo codice più facile da seguire.

L'uso di Intellisense è pigro? Scrive meno del nome intero. O ci sono cose che richiedono meno lavoro ma non meritano critiche? Penso che ci siano, e var è uno di questi.


6
+1, unica persona da notare che varnon ha nulla a che fare con Variant.
user7116,

27

Il tempo più probabile che ti servirà è per i tipi anonimi (dove è richiesto al 100%); ma evita anche la ripetizione per i casi banali e l'IMO rende la linea più chiara. Non ho bisogno di vedere il tipo due volte per una semplice inizializzazione.

Per esempio:

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

(per favore non modificare hscroll in quanto sopra - questo dimostra il punto !!!)

vs:

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

Vi sono, tuttavia, occasioni in cui ciò è fuorviante e può potenzialmente causare bug. Fare attenzione varse la variabile originale e il tipo inizializzato non erano identici. Per esempio:

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);

1
(per informazioni, puoi ottenere problemi simili su qualsiasi cosa in cui si tratti di una conversione di tipo implicita)
Marc Gravell

1
Non sono d'accordo con la parte che non vuoi vederlo due volte nella stessa riga. È possibile che in futuro non si crei direttamente la variabile dopo aver dichiarato (ad esempio in un if sotto la definizione) che potrebbe non essere direttamente chiaro quale sia il tipo. La maggior parte degli sviluppatori viene utilizzata per vedere il tipo direttamente all'inizio della riga, specialmente nel codice complesso che non si desidera rendere più difficile la lettura del codice.
Gertjan,

@TheVillageIdiot - Ho ripristinato la tua modifica, perché in questa occasione l'hscroll è legato al punto ;-p
Marc Gravell

2
@Gertjan - il mio cervello è limitato; se è complesso, non voglio vederlo due volte e devo iniziare il confronto (interfaccia / calcestruzzo / ecc.). Sono felice di vederlo una volta e pensare "digitato come uno di loro".
Marc Gravell

17

Un caso specifico in cui var è difficile: revisioni del codice offline, in particolare quelle fatte su carta.

Non puoi fare affidamento sui mouse-over per questo.


17
Perché diamine stai rivedendo il codice su carta? Pensa agli alberi! ;)
Dustman,

8
Puoi avere lo stesso problema senza usare var. Il problema non è var; il problema sono nomi di variabili errati. Se i nomi delle variabili sono ben scelti, l'uso di var non ha importanza.
Ryan Lundy,

Ho un ragazzo nella mia squadra che rivede il proprio codice e cerca bug, stampando il suo codice. Le sue pareti sono coperte di codice. Una volta sono entrato e aveva un'intera grande lavagna coperta con uno dei suoi esercizi di debug. Probabilmente era ~ 10000 LOC
Beep beep

I nomi delle variabili da soli non risolvono il problema a meno che non torni alla notazione ungherese in cui il tipo fa parte del nome.
Kevin Gale,

17

Non vedo quale sia il grosso problema ..

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

Hai ancora piena intelligenza su "qualcosa", e per ogni caso ambiguo hai i tuoi test unitari, giusto? ( Fai? )

Non è varchar, non è debole, e certamente non è una digitazione dinamica o debole. Sta fermando Maddnes in questo modo:

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

e riducendo quel disordine totale a:

var v = new List<somethinglongtypename>();

Bello, non abbastanza bello come:

v = List<somethinglongtypename>();

Ma allora è a questo che serve Boo .


il tipo di "qualcosa" è molto chiaro per il compilatore, internamente, il "var" viene impostato sul tipo restituito di "someMethod", è chiaro per il compilatore, ma potrebbe non essere chiaro per gli sviluppatori che lavorano al progetto. e Boo cresce rapidamente su di me.
stephenbayer,

No, v = List<somethinglongtypename>();non è nemmeno più bello. È importante distinguere tra l'introduzione di una nuova variabile e l'assegnazione a una variabile esistente.
HighCommander4,

Bene, se in precedenza hai assegnato "v" nell'ambito corrente, allora è assegnazione a un esistente. Altrimenti è assegnazione alla nuova variabile 'v'. Facile.
Frep D-Oronge,

17

Se qualcuno sta usando la varparola chiave perché non vuole "capire il tipo", questa è sicuramente la ragione sbagliata. La varparola chiave non crea una variabile con un tipo dinamico, il compilatore deve ancora conoscere il tipo. Poiché la variabile ha sempre un tipo specifico, il tipo dovrebbe anche essere evidente nel codice, se possibile.

Buoni motivi per usare la varparola chiave sono ad esempio:

  • Dove è necessario, cioè per dichiarare un riferimento per un tipo anonimo.
  • Dove rende il codice più leggibile, ovvero rimuovendo le dichiarazioni ripetitive.

Scrivere il tipo di dati spesso rende il codice più facile da seguire. Mostra i tipi di dati che stai utilizzando, in modo da non dover capire il tipo di dati prima di capire cosa fa il codice.


11

Considerato quanto sia potente Intellisense ora, non sono sicuro che var sia più difficile da leggere che avere variabili membro in una classe o variabili locali in un metodo che sono definite al di fuori dell'area dello schermo visibile.

Se hai una riga di codice come

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

È molto più facile o più difficile da leggere di:

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

In realtà non l'ho preso in considerazione, dall'altra domanda sembra che sia un punto abbastanza forte per un'altra volta usarlo.
Finglas,

Questo era fondamentalmente l'unico motivo per cui l'hanno implementato (oltre a poter dichiarare tipi anonimi, ma avrebbero potuto rendere "var" una parola chiave speciale che era solo per tipi anonimi.)
mqp

10

Penso che la cosa chiave con VAR sia usarla solo dove appropriato, cioè quando si fanno cose in Linq che facilita (e probabilmente in altri casi).

Se hai ottenuto un tipo di qualcosa nel allora si dovrebbe usarlo - non farlo è semplice pigrizia (al contrario di pigrizia creativa che è generalmente di essere incoraggiati - buoni programmatori spesso lavorano molto duramente per essere pigri e potrebbe essere considerato la fonte della cosa in primo luogo).

Un divieto generale è tanto grave quanto l'abuso del costrutto, ma deve esserci uno standard di codifica ragionevole.

L'altra cosa da ricordare è che non è un tipo VB var in quanto non può cambiare i tipi - è una variabile fortemente tipizzata è solo che il tipo viene dedotto (motivo per cui ci sono persone che sosterranno che non è irragionevole usarlo in, diciamo, un foreach ma non sarei d'accordo per ragioni di leggibilità e manutenibilità).

Ho il sospetto che questo funzionerà e funzionerà (-:

Murph


10

Certo, intè facile, ma quando il tipo di variabile è IEnumerable<MyStupidLongNamedGenericClass<int, string>>, var rende le cose molto più facili.


2
+1 per questo. intversus varè qualcosa di cui discutere, ma più tipi generici nidificati fanno varuna manna dal cielo. Questo è dove l'uso ripetuto del nome del tipo distrugge davvero la leggibilità del codice.
Chris Farmer,

Questo è assolutamente il motivo sbagliato per usarlo. Se il codice utilizza un tipo generico nidificato, è necessario derivarne una classe denominata specifica. Ad esempio: class IntStringEnumerator : IEnumerable<MyStupidLongNamedGenericClass<int, string>>e quindi utilizzare il nuovo nome. Ciò pulisce il codice e descrive meglio il tipo.
xxbbcc,

Va bene, ma il mio esempio era solo iperbole. IntStringEnumerator i = new IntStringEnumerator()sta ancora scrivendo troppo.
Blorgbeard esce il

9

Rubato dal post su questo numero di CodingHorror :


Sfortunatamente, tu e tutti gli altri avete praticamente sbagliato. Mentre sono d'accordo con te sul fatto che la ridondanza non è una buona cosa, il modo migliore per risolvere questo problema sarebbe stato fare qualcosa di simile al seguente:

MyObject m = new ();

O se stai passando parametri:

Persona p = new ("FirstName", "LastName);

Dove nella creazione di un nuovo oggetto, il compilatore deduce il tipo dal lato sinistro e non dal lato destro. Questo ha altri vantaggi rispetto a "var", in quanto potrebbe essere utilizzato anche nelle dichiarazioni di campo (ci sono anche alcune altre aree che potrebbero essere utili, ma non ci entrerò qui).

Alla fine, non intendeva ridurre la ridondanza. Non fraintendetemi, "var" è MOLTO importante in C # per tipi / proiezioni anonime, ma l'uso qui è proprio MODO (e lo dico da molto, molto tempo) mentre offuschi il tipo che viene usato. Doverlo digitare due volte è troppo spesso, ma dichiararlo zero volte è troppo poco.

Nicholas Paldino .NET / C # MVP il 20 giugno 2008 08:00


Immagino che la tua preoccupazione principale sia quella di dover digitare meno, quindi non c'è alcun argomento che ti impedirà di usarlo.

Se si sta solo andando a mai essere la persona che guarda il tuo codice, quindi chi se ne frega? Altrimenti, in un caso come questo:

var people = Managers.People

va bene, ma in un caso come questo:

var fc = Factory.Run();

mette in corto circuito qualsiasi deduzione di tipo immediata che il mio cervello potrebbe iniziare a formare dall '"inglese" del codice.

Altrimenti, usa il tuo miglior giudizio e la programmazione 'cortesia' verso gli altri che potrebbero dover lavorare sul tuo progetto.


4
I tuoi esempi sopra non sono un argomento per non usare var; sono un argomento per usare buoni nomi di variabili descrittive. Se, invece di [var fc = Factory.Run ();] avessi [bool fc = Factory.Run ();], il codice non diventerebbe più chiaro.
Ryan Lundy,

9

L'uso al varposto del tipo esplicito rende molto più semplici i refactoring (quindi devo contraddire i poster precedenti che volevano dire che non faceva alcuna differenza o era puramente "zucchero sintattico").

È possibile modificare il tipo restituito dei metodi senza modificare tutti i file in cui viene chiamato questo metodo. Immaginare

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

che viene utilizzato come

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

Se si desidera refactoring SomeMethod()per restituire un IEnumerable<MySecondClass>, è necessario modificare la dichiarazione della variabile (anche all'interno diforeach ) in ogni punto in cui è stato utilizzato il metodo.

Se scrivi

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

invece, non devi cambiarlo.


d'accordo - chiedendomi perché questo piacevole effetto collaterale non sia propagandato tanto quanto alcuni degli altri, i pro più soggettivi nelle risposte più popolari.
fieldingmellish il

Mi è successo oggi. Ho una classe di fabbrica che restituisce l'istanza di una classe MainMenu. Oggi ho creato un MainMenu2 con la stessa interfaccia di MainMenu. Il mio codice di tutte le app non viene toccato dopo la modifica!
Marco Staffoli,

8

@aku: un esempio sono le revisioni del codice. Un altro esempio sono gli scenari di refactoring.

Fondamentalmente non voglio andare a caccia di tipi con il mouse. Potrebbe non essere disponibile.


2
È interessante affermarlo perché var può semplificare il refactoring. Se hai usato var non è necessario. Ora puoi sempre fare affidamento sugli strumenti di refactoring dell'IDE, ma sai, puoi sempre fare affidamento anche sull'IDE per il tipo :)
Fred,

8

È una questione di gusti. Tutto questo agitarsi sul tipo di una variabile scompare quando ti abitui alle lingue tipizzate in modo dinamico. Cioè, se mai inizi a piacerti (non sono sicuro che tutti possano, ma lo faccio).

C # varè piuttosto interessante in quanto sembra una tipizzazione dinamica, ma in realtà è una tipizzazione statica - il compilatore ne applica un uso corretto.

Il tipo della tua variabile non è poi così importante (è stato detto prima). Dovrebbe essere relativamente chiaro dal contesto (le sue interazioni con altre variabili e metodi) e il suo nome - non aspettarti CustomerList contenga un int...

Sto ancora aspettando di vedere cosa pensa il mio capo di questa faccenda: ho una coperta "vai avanti" per usare qualsiasi nuovo costrutto in 3.5, ma cosa faremo per la manutenzione?


7

Nel tuo confronto tra IEnumerable<int> e IEnumerable<double>non devi preoccuparti: se passi il tipo sbagliato il tuo codice non verrà compilato comunque.

Non c'è alcuna preoccupazione per tipo di sicurezza, come varè non dinamica. È solo una magia del compilatore e qualsiasi tipo di chiamata non sicura che farai verrà catturata.

Var è assolutamente necessario per 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
    };

Ora guarda anonEnumeration in intellisense e sembrerà qualcosa del genereIEnumerable<'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
}

Il compilatore C # è piuttosto intelligente: i tipi di anoni generati separatamente avranno lo stesso tipo generato se le loro proprietà corrispondono.

Al di fuori di questo, fintanto che hai intellisense ha senso usare varovunque il contesto sia chiaro.

//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;

Si prega di sbarazzarsi IQueriable<T>prima di ripetere: anonEnumeration.ToList();
David Diez,

@DavidDiez potresti riformulare? La tua affermazione non ha senso. Nessuno dei miei riferimenti a frammenti di codice IQueryableo.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 };non restituisce un IQueriable<T>?
David Diez,

1
@DavidDiez dipende da ciò che AllPosts()ritorna - il richiedente si riferisce List<T>quindi ho pensato che. In tal caso il risultato è che anonEnumerationsarà di tipo IEnumerable<'a>. Ora, se AllPosts()restituisce IQueryable<T>invece, allora anonEnumerationdiventerà IQueryable<'a>(nota no iin Queryable) - tuttavia in quel caso il mio codice funziona ancora perché IQueryable<T>implementa IEnumerable<T>. Ci sono un sacco di domande e risposte migliori qui sulle distinzioni tra loro - qui il mio caso è che 'aè anonimo e varti consente di assegnarlo a una variabile tipizzata staticamente.
Keith,

Ohh capisco, grazie per averlo spiegato :) Il mio commento è stato perché iterare una IQueryable<T>non è una buona pratica perché in ogni iterazione stai facendo una dichiarazione di lettura in DB. Assicurati di *.ToList() IQueryable<T>prima di iterarli
David Diez,

7

Immagino che dipenda dalla tua prospettiva. Personalmente non ho mai avuto difficoltà a capire un pezzo di codice a causa divar "uso improprio", e i miei colleghi e lo uso abbastanza dappertutto. (Sono d'accordo sul fatto che Intellisense sia di grande aiuto in questo senso.) Accolgo con favore come un modo per rimuovere l'innesto ripetitivo.

Dopotutto, se le dichiarazioni piacciono

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

se fosse davvero così impossibile da gestire, nessuno userebbe le lingue tipizzate dinamicamente.


Presumibilmente in .Net 4 dove i tipi dinamici sono luoghi comuni, questo diventerà più importante?
Colin Desmond,

2
Al contrario, se ora sei confuso da "var", mi aspetterei che tu sia ulteriormente confuso da "dinamico". Dio vieta a chiunque di dichiarare mai una dinamica e quindi di fare un riferimento ad essa usando "var" :)
mqp

Intendevo qualcosa come dinamico d = 52; var x = d; che dovrebbe andare bene.
mqp,

7

Uso var solo quando è chiaro per vedere quale tipo viene utilizzato.

Ad esempio, userei var in questo caso, perché puoi vedere immediatamente che x sarà del tipo "MyClass":

var x = new MyClass();

NON userei var in casi come questo, perché è necessario trascinare il mouse sul codice e guardare il suggerimento per vedere che tipo restituisce MyFunction:

var x = MyClass.MyFunction();

In particolare, non uso mai var nei casi in cui il lato destro non è nemmeno un metodo, ma solo un valore:

var x = 5;

(perché il compilatore non può sapere se voglio un byte, short, int o altro)


Se il lato destro non è abbastanza chiaro da giustificare l'uso var, varnon è questo il problema: il lato destro è il problema. Non è abbastanza descrittivo . Customer c = GetContext()non è ancora chiaro e non è meglio dell'uso var.
JulianR

6

Per me l'antipatia nei confronti varillustra perché il bilinguismo in .NET è importante. Per quei programmatori C # che hanno anche eseguito VB .NET, i vantaggi di varsono intuitivamente ovvi. La dichiarazione C # standard di:

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

è l'equivalente, in VB .NET, di digitare questo:

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

Tuttavia, nessuno lo fa in VB .NET. Sarebbe sciocco, perché dalla prima versione di .NET sei stato in grado di farlo ...

Dim whatever As New List(Of String)

... che crea la variabile e inizializza tutto in una linea ragionevolmente compatta. Ah, ma cosa succede se si desidera un IList<string>, non un List<string>? Bene, in VB .NET ciò significa che devi fare questo:

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

Proprio come avresti dovuto fare in C # e ovviamente non puoi usarlo varper:

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

Se hai bisogno che il tipo sia qualcosa di diverso, può essere. Ma uno dei principi di base di una buona programmazione è la riduzione della ridondanza, ed è esattamente ciò che fa var.


1
È divertente menzionare il bilinguismo come qualcosa che promuove l'uso del var. Il mio antagonismo verso la parola chiave var deriva direttamente dalla mia fluidità in javascript! :)
urig

varin C # non ha alcuna connessione con varin JavaScript. Una varvariabile dichiarata in C # è fortemente tipizzata.
Ryan Lundy,

6

Usalo per tipi anonimi - ecco a cosa serve. Qualsiasi altra cosa è un uso troppo lontano. Come molte persone cresciute in C, sono abituata a guardare a sinistra della dichiarazione per il tipo. Non guardo sul lato destro se non devo. L'utilizzo vardi una vecchia dichiarazione mi fa fare tutto il tempo, che personalmente trovo scomodo.

Coloro che dicono "non importa, usa ciò di cui sei felice" non vedono l'intera immagine. Ognuno raccoglierà il codice di altre persone in un punto o nell'altro e dovrà occuparsi delle decisioni prese nel momento in cui lo ha scritto. È abbastanza grave dover affrontare convenzioni di denominazione radicalmente diverse, o - i classici aspetti negativi - stili di rinforzo, senza aggiungere tutto ' varo no' al mix. Il caso peggiore sarà quando un programmatore non ha usato vare poi arriva un manutentore che lo adora e estende il codice utilizzandolo. Quindi ora hai un casino disgraziato.

Gli standard sono una buona cosa proprio perché significano che hai molte più probabilità di essere in grado di raccogliere codice casuale ed essere in grado di farlo rapidamente. Più cose sono diverse, più diventa difficile. E passare allo stile "var ovunque" fa una grande differenza.

Non mi dispiace digitare in modo dinamico e non mi dispiace digitare in modo implicito, in lingue progettate per loro. Mi piace abbastanza Python. Ma C # è stato progettato come un linguaggio tipizzato in modo statico esplicito ed è così che dovrebbe rimanere. Violare le regole per i tipi anonimi era abbastanza brutto; lasciare che le persone lo facciano ancora di più e rompere ancora di più gli idiomi della lingua è qualcosa di cui non sono contento. Ora che il genio è fuori dalla bottiglia, non tornerà mai più dentro. C # diventerà balcanizzato nei campi. Non bene.


7
Wow. Ignorare tutti gli argomenti portati avanti in questo thread finora e reimpostare l'intera discussione è piuttosto un risultato.
Konrad Rudolph,

Questo 100% descrive cosa provo per 'var', in particolare dal punto di vista della raccolta del codice di qualcun altro. L'uso di var cambia radicalmente l'attività a portata di mano se è disseminata dappertutto. +1
Simone,

6

Molte volte durante i test, mi ritrovo ad avere un codice come questo:

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

Ora, a volte, voglio vedere cosa contiene SomeOtherThing stesso, SomeOtherThing non è lo stesso tipo restituito da CallMethod (). Dal momento che sto usando var, cambio solo questo:

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

a questo:

var something = myObject.SomeProperty.SomeOtherThing;

Senza var, dovrei continuare a cambiare anche il tipo dichiarato sul lato sinistro. So che è minore, ma è estremamente conveniente.


6

Per gli affiliati che pensano di varrisparmiare tempo, sono necessari meno tasti per digitare:

StringBuilder sb = new StringBuilder();

di

var sb = new StringBuilder();

Contali se non mi credi ...

19 contro 21

Spiegherò se devo, ma provalo ... (a seconda dello stato attuale del tuo intellisense potresti dover digitare un paio in più per ognuno)

Ed è vero per ogni tipo che ti viene in mente !!

La mia sensazione personale è che var non dovrebbe mai essere usato, tranne dove il tipo non è noto perché riduce la leggibilità del riconoscimento nel codice. Il cervello impiega più tempo a riconoscere il tipo di una linea completa. I vecchi timer che comprendono il codice e i bit della macchina sanno esattamente di cosa sto parlando. Il cervello elabora in parallelo e quando usi var lo costringi a serializzare il suo input. Perché qualcuno dovrebbe voler far lavorare di più il cervello? Ecco a cosa servono i computer.


Trovo la ripetizione di stringBuilder sb = new StringBuilder () disordinata e più lunga da riconoscere chiaramente. È un rumore extra. Il problema è che determinare cosa fa e non costituisce un ulteriore sforzo intellettuale per comprendere un po 'di codice è piuttosto soggettivo!
ljs

"var non dovrebbe mai essere usato tranne dove il tipo non è noto ..." - Puoi SEMPRE conoscere il tipo, così come il compilatore. Non si tratta di una digitazione dinamica, consente solo al compilatore di determinare il tipo per te. Ma il tipo non è mai sconosciuto.
Gabriel Magana,

5

Ho diviso var su tutti i luoghi, i luoghi solo discutibili per me sono i tipi corti interne, ad esempio, io preferisco int i = 3;sopravar i = 3;


5

Può certamente rendere le cose più semplici, dal codice che ho scritto ieri:

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

Ciò sarebbe estremamente prolisso senza var.

Addendum: un po 'di tempo trascorso con un linguaggio con una reale deduzione del tipo (es. F #) mostrerà quanto sono bravi i compilatori a ottenere il tipo di espressioni giusto. Certamente ha significato che tendo a usare varil più possibile e l'uso di un tipo esplicito ora indica che la variabile non è del tipo dell'espressione inizializzante.


Sì, i compilatori sono più intelligenti di noi, superalo!
Benjol,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.