Utilisation du mot clé var en C #

406

Après discussion avec des collègues concernant l'utilisation du mot-clé 'var' en C # 3, je me demandais ce que les gens pensaient des utilisations appropriées de l'inférence de type via var?

Par exemple, j'ai plutôt utilisé paresseusement var dans des circonstances douteuses, par exemple: -

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.

Les utilisations les plus légitimes de var sont les suivantes: -

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

Fait intéressant, LINQ semble être un peu une zone grise, par exemple: -

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

Il est clair quels seront les résultats dans la mesure où ce sera un type qui implémente IEnumerable, mais ce n'est pas tout à fait évident de la même manière qu'un var déclarant un nouvel objet.

C'est encore pire quand il s'agit de LINQ aux objets, par exemple: -

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

Ce n'est pas mieux que l'équivilent foreach (var item dans someList) {// ...} équivilent.

Il y a une réelle inquiétude à propos de la sécurité des types ici - par exemple, si nous devions placer les résultats de cette requête dans une méthode surchargée qui acceptait IEnumerable <int> et IEnumerable <double>, l'appelant pourrait par inadvertance transmettre le mauvais type.

var ne maintenir typage fort , mais la question est de savoir s'il est dangereux pour le type de ne pas être immédiatement apparent sur la définition, ce qui est magnifié lorsque Surcharges moyennes erreurs du compilateur risquent de ne pas être émis lorsque vous passez accidentellement le mauvais type à une méthode.

ljs
la source
68
L'utilisation de var est très bien, mais "je n'ai pas besoin de comprendre le type" semble être une très mauvaise raison de l'utiliser ... vous êtes censé savoir quel est le type, var n'est qu'un raccourci pour éviter de le taper
Thomas Levesque
53
var i = 0;== échouer! var c = new CrazyFrigginLongClassName();== gagner!
dotjoe
6
"Var me rappelle également le type de variante VB / VBA. Il avait également sa place. Je me souviens (il y a de nombreuses années) que son utilisation était de type peu souhaitable et qu'il était plutôt gourmand en ressources." <- montre que c'est une question difficile car le type 'var' de C # n'a rien à voir avec le type de variante VB / VBA.
user7116
20
var readabilityBeDamned = true;
spoulson
9
Le problème avec tous les exemples mentionnés ici est que nous examinons UNE seule ligne de code. Quand je vois ligne après ligne des déclarations "var", l'une après l'autre, ça devient incontrôlable. La lisibilité est subjective, mais je trouve que var est beaucoup plus utilisé que respectueusement.
jro

Réponses:

293

Je pense toujours que le varcode peut être plus lisible dans certains cas. Si j'ai une classe Customer avec une propriété Orders et que je veux l'attribuer à une variable, je vais simplement faire ceci:

var orders = cust.Orders;

Peu m'importe si Customer.Orders l'est IEnumerable<Order>, ObservableCollection<Order>ou BindingList<Order>- tout ce que je veux, c'est garder cette liste en mémoire pour l'itérer ou obtenir son nombre ou quelque chose plus tard.

Comparez la déclaration ci-dessus avec:

ObservableCollection<Order> orders = cust.Orders;

Pour moi, le nom du type est juste du bruit. Et si je reviens en arrière et que je décide de changer le type de client, je descends la piste (disons de ObservableCollection<Order>à IList<Order>) alors je dois aussi changer cette déclaration - quelque chose que je n'aurais pas à faire si j'avais utilisé var dans le premier endroit.

Matt Hamilton
la source
48
J'aime avoir le type explicite devant moi lorsque je lis du code. Comment puis-je savoir ce que "cust.Orders" est ici sans le type? Oui, je pourrais survoler ma souris pour le savoir, mais pourquoi devrais-je le faire? :)
Jon Tackabury
77
Mais le fait est qu'en général, cela n'a pas d'importance. Fourni cust.Orders est quelque chose que vous pouvez énumérer (par exemple foreach over), peu importe le type. Le code supplémentaire empêche simplement de lire l'intention.
Matt Hamilton,
67
Mais si vous n'avez besoin que de cust.Orders, c'est "quelque chose que vous pouvez énumérer", le déclarer comme un IEnumerable <Order> ne rend-il pas cette exigence explicite et claire? Le déclarer comme var signifie que vous perdez effectivement cette exigence.
GrahamS
5
@jon et comment les commandes IEnumerbal = cust.Orders foreach (var order in Orders) font-elles une différence? la seule chose que IEnumerable dit, c'est que vous pouvez le mettre dans un foreach mais vous le saviez déjà à partir de la ligne ci
Rune FS
18
"la seule chose que IEnumerable dit, c'est que vous pouvez le mettre dans un foreach" - il exprime également l'intention que la seule chose que vous pouvez faire est d'énumérer. L'utilisation de var donne accès à et intellisense pour les membres publics du type de collection concret.
Joe
167

J'utilise varbeaucoup. Il a été critiqué que cela diminue la lisibilité du code, mais aucun argument pour soutenir cette affirmation.

Certes, cela peut signifier que le type auquel nous avons affaire n'est pas clair. Et alors? C'est en fait le point d'une conception découplée. Lorsque vous traitez avec des interfaces, vous n'êtes absolument pas intéressé par le type d'une variable. varprend ce beaucoup plus loin, vrai, mais je pense que l'argument reste le même d'un point de vue de la lisibilité: Le programmeur ne devrait pas vraiment être intéressé par le type de la variable mais plutôt ce qu'est une variable fait . C'est pourquoi Microsoft appelle également l'inférence de type «typage de canard».

Alors, que fait une variable lorsque je la déclare en utilisant var? Facile, il fait tout ce qu'IntelliSense me dit de faire. Tout raisonnement sur C # qui ignore l'IDE est loin de la réalité. En pratique, chaque code C # est programmé dans un IDE qui prend en charge IntelliSense.

Si j'utilise une varvariable déclarée et que je ne sais pas à quoi sert la variable, il y a quelque chose de fondamentalement mauvais avec mon code. varn'est pas la cause, elle rend seulement les symptômes visibles. Ne blâmez pas le messager.

Maintenant, l'équipe C # a publié une directive indiquant que le codage vardoit seulement être utilisé pour capturer le résultat d'une déclaration de LINQ qui crée un type anonyme (car ici, nous avons pas d' alternative réelle à var). Eh bien, vissez ça. Tant que l'équipe C # ne me donnera pas d'argument valable pour cette directive, je vais l'ignorer parce qu'à mon avis professionnel et personnel, c'est du pur baloney. (Désolé; je n'ai aucun lien vers la ligne directrice en question.)

En fait, il y a (superficiellement) de bonnes explications sur les raisons pour lesquelles vous ne devriez pas utiliser, varmais je pense toujours qu'elles sont largement fausses. Prenons l'exemple de la «possibilité de recherche»: l'auteur affirme qu'il varest difficile de rechercher des endroits où il MyTypeest utilisé. Droite. Les interfaces aussi. En fait, pourquoi voudrais-je savoir où la classe est utilisée? Je serais peut-être plus intéressé par l'endroit où il est instancié et cela sera toujours consultable car quelque part son constructeur doit être invoqué (même si cela se fait indirectement, le nom du type doit être mentionné quelque part).

Konrad Rudolph
la source
14
Dans n'importe quel IDE décent, vous n'utilisez pas de recherche de texte pour obtenir l'utilisation des classes, vous obtenez l'IDE pour le faire en fonction de son arbre d'analyse ou, sinon, il identifie les types d'objets. Puisque nous parlons de frappe statique, cela trouvera tout sauf les types anonymes.
Dustman
6
Je détesterais hériter de 100 000 lignes de source sans documentation et utilisation généralisée de var. Surtout si vous combinez var avec des noms de variables peu utiles. Je pourrais le voir utile lors de l'illustration d'un point (ou lorsqu'il s'agit de types anonymes) mais dans le code de production?
Shea
7
Arnshea: vous avez déjà signalé le vrai problème: les noms de variables inutiles et la documentation manquante . Je ne vois vraiment pas ce qui varcontribue à la confusion. Certes, il peut y avoir des cas où il est important de souligner le type / la taille d'une variable (par exemple les opérations sur les bits de bas niveau). C'est bien: personne n'a jamais prétendu que cela vardevrait être utilisé exclusivement. La règle est simple: si cela crée vraiment de la confusion, ne l'utilisez pas.
Konrad Rudolph
17
Chaque exemple opposé à var que j'ai vu suppose que le programmeur utilisera des noms de variables sans signification. Mais c'est peut-être pourquoi var est mieux que de spécifier explicitement un type: cela oblige le programmeur à trouver de bons noms de variables.
Ryan Lundy le
16
Microsoft appelle également l'inférence de type «typage de canard». - le font-ils vraiment? Je serais choqué ...
Anton Tykhyy
118

Var, à mon avis, en C # est une bonne chose tm . Toute variable ainsi typée est toujours fortement typée, mais elle obtient son type du côté droit de l'affectation où elle est définie. Étant donné que les informations de type sont disponibles sur le côté droit, dans la plupart des cas, il est inutile et trop verbeux de devoir également les saisir sur le côté gauche. Je pense que cela augmente considérablement la lisibilité sans diminuer la sécurité du type.

De mon point de vue, l'utilisation de bonnes conventions de dénomination pour les variables et les méthodes est plus importante du point de vue de la lisibilité que les informations de type explicites. Si j'ai besoin des informations de type, je peux toujours survoler la variable (en VS) et l'obtenir. En règle générale, cependant, les informations de type explicites ne devraient pas être nécessaires au lecteur. Pour le développeur, dans VS, vous obtenez toujours Intellisense, quelle que soit la façon dont la variable est déclarée. Cela dit, il peut toujours y avoir des cas où il est logique de déclarer explicitement le type - peut-être avez-vous une méthode qui renvoie un List<T>, mais vous voulez le traiter comme unIEnumerable<T>dans votre méthode. Pour vous assurer que vous utilisez l'interface, la déclaration de la variable du type d'interface peut rendre cela explicite. Ou, peut-être, vous voulez déclarer une variable sans valeur initiale - car elle obtient immédiatement une valeur basée sur une condition. Dans ce cas, vous avez besoin du type. Si les informations de type sont utiles ou nécessaires, allez-y et utilisez-les. Je pense, cependant, que ce n'est généralement pas nécessaire et que le code est plus facile à lire sans lui dans la plupart des cas.

tvanfosson
la source
3
Je suis d'accord dans l'ensemble. À mon avis, le point clé est d'être certain que l'intention est claire. Si ce n'est pas clair pour la majorité des développeurs de l'équipe, c'est néfaste, pas utile. Cela dit, je suis personnellement un ÉNORME fan de cela, mais j'ai dû me restreindre un peu lorsque d'autres développeurs de mon équipe ont eu du mal à déterminer mon intention. Allez comprendre.
Steve Brouillard
3
Eh, je trouve plus facile à lire lorsque le type est à gauche. En utilisant ReSharper, je n'ai pas besoin de retaper le type à droite de toute façon, donc cela ne me dérange pas.
BlueRaja - Danny Pflughoeft
1
@BlueRaja - Je trouve que l'utilisation de bons noms de variables élimine généralement la nécessité de se soucier du type réel pour comprendre. Intellisense est toujours disponible sur les variables définies "var", donc je n'ai pas besoin de connaître le type pour choisir une méthode / propriété dessus lors du codage.
tvanfosson
2
Il ne s'agit pas tant de coder que de lire le code.
BlueRaja - Danny Pflughoeft
1
Je dois donc être sur le côté épais, j'ai besoin de bons noms de méthode et de variable et d' une compréhension des types utilisés pour pouvoir comprendre correctement le code que je lis. Je pense que vous avez raison, bien que cela soit symptomatique de problèmes plus importants. Un de confiance. Pour être sûr que le code fait ce qu'il semble faire, vous devez être sûr des types utilisés.
AnthonyWJones
91

Aucun de ces éléments n'est absolument vrai; varpeut avoir des effets à la fois positifs et négatifs sur la lisibilité. À mon avis, vardoit être utilisé lorsque l'une des conditions suivantes est vraie:

  1. Le type est anonyme (eh bien, vous n'avez pas le choix ici, car il doit être var dans ce cas)
  2. Le type est évident en fonction de l'expression assignée (c.-à-d. var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating())

varn'a pas d'impact sur les performances, car c'est du sucre syntaxique; le compilateur déduit le type et le définit une fois qu'il est compilé en IL; il n'y a rien de vraiment dynamique à ce sujet.

Adam Robinson
la source
1
d'accord sur les deux, bien que j'ai de longues restrictions sur le deuxième cas, si un type est aussi long, c'est généralement un type générique avec beaucoup d'arguments génériques imbriqués, dans ce cas, un "ShortType équivalent fortement typé à TypeWithAReallyLongNameTheresNoSenseRepeating" a plus de sens
Ion Todirel
12
Je n'ai aucune envie de déclencher une guerre de religion, mais j'ai personnellement tendance à être en désaccord avec Ion. Je préférerais de loin un nom de type très long mais très précis (ala Oncle Bob Martin) plutôt qu'un nom de type abrégé et éventuellement ambigu. J'ajouterai la mise en garde que je ne suis pas d'accord pour gonfler artificiellement la longueur du nom non plus. Si 5 caractères créent un nom concis qui montre clairement l'intention, alors utilisez 5 et non 25.
Steve Brouillard
2
@Steve: Je dois être d'accord avec vous; la création d'un "type court" (que je suppose que vous entendez comme héritant du type générique spécifique uniquement dans le but de raccourcir le nom) n'est pas une bonne pratique; cela vous obligera à dupliquer et à passer par tous les constructeurs du type générique, ainsi qu'à vous empêcher de passer un type différent qui hérite du type générique à la fonction. Vous utilisez l'héritage comme typedefquand il ne l'est pas.
Adam Robinson,
7
A utiliser varlorsque le type est évident? Peut-être, mais le vrai gain est lorsque le type n'a pas d'importance. Si vous faites des choses comme var customers = whatever; var query = from c in customers select stuffça, peu importe le type exact de «clients». Il est évident que vous pouvez l'utiliser, et cela suffit. Et si le type réel est encombrant, cela vaut la peine de le supprimer.
Joren
2
@Kristoffer: Je peux comprendre vouloir éliminer le désordre des balises, mais les encapsuler dans une classe n'est pas (IMO) une alternative acceptable, car vous supprimez alors la possibilité de toute autre classe enfant (légitime) de ce type générique d'être un paramètre valide. Je préfère utiliser une using ShortType = LongGenericType<A,B,C>directive en haut d'un fichier, car cela donne la même lisibilité, ne nécessite pas que vous recréiez les constructeurs et n'élimine pas les classes enfants d'être des candidats.
Adam Robinson,
68

De Eric Lippert, ingénieur principal en conception de logiciels dans l'équipe C #:

Pourquoi le varmot - clé a- t-il été introduit?

Il y a deux raisons, une qui existe aujourd'hui, une qui apparaîtra dans 3.0.

La première raison est que ce code est incroyablement moche à cause de toute la redondance:

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

Et c'est un exemple simple - j'ai écrit pire. Chaque fois que vous êtes obligé de taper exactement la même chose deux fois, c'est une redondance que nous pouvons supprimer. Beaucoup plus agréable à écrire

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

et laissez le compilateur comprendre ce que le type est basé sur l'affectation.

Deuxièmement, C # 3.0 introduit des types anonymes. Étant donné que les types anonymes par définition n'ont pas de nom, vous devez pouvoir déduire le type de la variable à partir de l'expression d'initialisation si son type est anonyme.

Je souligne. L'article entier, C # 3.0 est toujours typé statiquement, honnêtement! , et les séries suivantes sont plutôt bonnes.

C'est pour ça var. D'autres utilisations ne fonctionneront probablement pas aussi bien. Toute comparaison avec JScript, VBScript ou le typage dynamique est totale. Notez à nouveau, varest nécessaire pour que certaines autres fonctionnalités fonctionnent dans .NET.

Dustman
la source
Je trouve étrange l'argument de Lippert. Personne ne tape le nom de la deuxième classe, ils ont laissé Intellisense l'écrire pour eux, mais il se retourne et prétend que var est meilleur parce que le compilateur / Intellisense le règle. Vous ne pouvez pas l'avoir dans les deux sens!
Dave
5
L'équipe C # ne contrôle pas l'intellisense, elle contrôle le compilateur. Quoi qu'il en soit, ce n'est pas le problème principal. Je ne pense pas que var aurait fait les 100 points sur la sauvegarde de la frappe seule.
Dustman
@Dustman: var ne sauvegarde pas du tout la saisie. Cela vous fait écrire plus!
Piotr Perak
53

Je pense que l'utilisation de var doit être associée à des noms de variables judicieusement choisis.

Je n'ai aucun problème à utiliser var dans une instruction foreach, à condition que ce ne soit pas comme ceci:

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

Si c'était plus comme ça:

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

... alors quelqu'un lisant le code serait beaucoup plus susceptible de comprendre ce qu'est une "liste". Si vous contrôlez le nom de la variable de liste elle-même, c'est encore mieux.

La même chose peut s'appliquer à d'autres situations. C'est assez inutile:

var x = SaveFoo(foo);

... mais cela a du sens:

var saveSucceeded = SaveFoo(foo);

Chacun à sa façon, je suppose. Je me suis retrouvé à faire cela, ce qui est juste fou:

var f = (float)3;

J'ai besoin d'une sorte de programme var en 12 étapes. Je m'appelle Matt et j'utilise (ab) var.

Matt Hamilton
la source
6
Eh bien la seule chose qui cloche avec "var f = (float) 3;" est qu'il devrait être "var f = 3f" ou "var f = 3.0 (car la précision simple est nulle)".
MichaelGG
3
Hé ouais 3f ou 3.0 est le chemin à parcourir! Nous, les maniaques var, devons rester ensemble!
Matt Hamilton,
27
Le vrai problème dans ce premier exemple est "liste", pas "c". "liste" de quoi ? "liste" doit être renommé "clients", ou "clientsWhoOweMoney", ou "clients actuels", ou quelque chose de beaucoup plus descriptif. Et une fois que vous avez cela, le "c" peut rester tel quel, car vous savez déjà ce qu'il contiendra.
Ryan Lundy
4
Salut Matt! Je m'appelle Kenny et je suis un varaddict.
kenny
var MattHamil = "Luke Skywalker"; // en a retiré une tonne
Binoj Antony
40

Nous avons adopté l'ethos "Code pour les personnes, pas pour les machines", basé sur l'hypothèse que vous passez plusieurs fois plus longtemps en mode maintenance que sur les nouveaux développements.

Pour moi, cela exclut l'argument selon lequel le compilateur "sait" de quel type est la variable - bien sûr, vous ne pouvez pas écrire de code non valide la première fois car le compilateur arrête la compilation de votre code, mais lorsque le développeur suivant lit le code en 6 mois, ils doivent être capables de déduire ce que fait la variable correctement ou incorrectement et d'identifier rapidement la cause des problèmes.

Donc,

var something = SomeMethod();

est interdit par nos normes de codage, mais ce qui suit est encouragé dans notre équipe car il augmente la lisibilité:

var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
   DoWork( item ); 
}
Dexter
la source
4
J'ai trouvé que ("Code pour les personnes, pas pour les machines") est une excellente ligne directrice - le suivre peut entraîner un meilleur code et éviter une optimisation prématurée.
Thanatos
3
Je ne reçois pas var list = new KeyValuePair <string, double>? Pour moi, une liste peut avoir plus que quelque chose.
TTT
"Code pour les gens, pas pour les machines" - amen.
user1068352
39

Ce n'est pas mal, c'est plus une chose stylistique, qui a tendance à être subjective. Il peut ajouter des incohérences, lorsque vous utilisez var et quand vous ne l'utilisez pas.

Un autre cas de préoccupation, dans l'appel suivant, vous ne pouvez pas dire simplement en regardant le code du type retourné par CallMe:

var variable = CallMe();

C'est ma principale plainte contre var.

J'utilise var lorsque je déclare des délégués anonymes dans les méthodes, en quelque sorte var semble plus propre que si je l'utilisais Func. Considérez ce code:

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

EDIT : mise à jour du dernier exemple de code basé sur l'entrée de Julian

Ion Todirel
la source
3
Mais avez-vous vraiment besoin de connaître le type sur cette ligne? Vous savez que CallMe renvoie quelque chose; ne suffit-il pas de savoir qu'une variable locale nommée variableest créée? Sauf si vous développez votre exemple, ce n'est pas une plainte très solide, OMI.
Randolpho
2
Il ne s'agit pas de ne pas être verbeux, il ne s'agit pas de laisser le compilateur faire le sucre de syntaxe pour vous. Considérez ceci: var getter ..., maintenant ce Func <object> getter ..., avec la seconde vous savez que vous n'avez pas à fournir de paramètres et ce qu'il retourne. Vous savez dès le départ «que faire» et pouvez prendre des décisions plus rapidement, lorsque vous concevez quelque chose ou refactorisez. Avoir toutes les informations à portée de main est plus important que quelques caractères supplémentaires. Cela ne peut être apprécié que lorsque vous travaillez avec beaucoup de code.
Ion Todirel
2
Puisque nous parlons tous de Visual Studio de toute façon, quel est le problème de passer votre souris sur la variable pendant une seconde et de voir de quel type s'agit-il? Bien mieux que de courir à la déclaration de toute façon.
Rubys
3
Les noms de variables et de fonctions génériques ( variable, CallMe) sont de mauvais exemples. Cependant, si CallMe()c'était une fonction dans une sorte d '"application téléphonique", cela var call = CallMe(); .... call.HangUp();aurait beaucoup plus de sens.
Danko Durbić
3
@Randolpho: "quel est le problème de placer votre souris sur la variable pendant une seconde et de voir de quel type s'agit-il?" Il ajoute du temps à la surcharge de maintenance ... plus une seconde n'est que le temps de survol plutôt que de compter le changement de contexte du clavier vers la souris. Je ne sais pas pour vous, mais je travaille avec un délai. Chaque fois que je dois survoler une variable pour découvrir de quel type il s'agit, c'est du temps que j'aurais mieux fait de résoudre un problème.
Powerlord
36

Var n'est pas du tout comme variante. La variable est toujours fortement typée, c'est juste que vous n'appuyez pas sur les touches pour l'obtenir de cette façon. Vous pouvez survoler dans Visual Studio pour voir le type. Si vous lisez du code imprimé, il est possible que vous deviez réfléchir un peu pour déterminer le type. Mais il n'y a qu'une seule ligne qui le déclare et beaucoup de lignes qui l'utilisent, donc donner des noms décents est toujours le meilleur moyen de rendre votre code plus facile à suivre.

L'utilisation d'Intellisense est-elle paresseuse? C'est moins en tapant que le nom entier. Ou y a-t-il des choses qui demandent moins de travail mais ne méritent pas d'être critiquées? Je pense qu'il y en a, et var en fait partie.

Kate Gregory
la source
6
+1, seule personne à noter qui varn'a rien à voir avec Variant.
user7116
27

Le temps le plus probable dont vous aurez besoin est pour les types anonymes (où il est requis à 100%); mais cela évite également la répétition pour les cas triviaux, et l'OMI rend la ligne plus claire. Je n'ai pas besoin de voir le type deux fois pour une simple initialisation.

Par exemple:

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

(veuillez ne pas modifier le hscroll ci-dessus - cela prouve un peu le point !!!)

contre:

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

Il y a cependant des occasions où cela est trompeur et peut potentiellement causer des bugs. Soyez prudent varsi la variable d'origine et le type initialisé n'étaient pas identiques. Par exemple:

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
la source
1
(pour info, vous pouvez obtenir des problèmes similaires sur tout ce qui est une conversion de type implicite)
Marc Gravell
1
En désaccord avec la partie que vous ne voulez pas voir deux fois sur la même ligne. Il est possible qu'à l'avenir vous ne créiez pas directement la variable après avoir déclaré (par exemple dans un si en dessous de la définition), il pourrait ne pas être directement clair quel est le type. La plupart des développeurs ont l'habitude de voir le type directement au début de la ligne, en particulier dans le code complexe, vous ne voulez pas rendre la lecture du code plus difficile.
Gertjan
@TheVillageIdiot - J'ai annulé votre montage, car à cette occasion le hscroll est lié au point ;-p
Marc Gravell
2
@Gertjan - mon cerveau est limité; s'il est complexe, je ne veux pas le voir deux fois et je dois commencer à comparer (interface / béton / etc). Je suis heureux de le voir une fois et de penser "tapé comme l'un d'eux".
Marc Gravell
17

Un cas spécifique où var est difficile: les révisions de code hors ligne, en particulier celles effectuées sur papier.

Vous ne pouvez pas compter sur les survols pour cela.

Jon Limjap
la source
17
Pourquoi diable révisez-vous le code sur papier? Pensez aux arbres! ;)
Dustman
8
Vous pouvez avoir le même problème sans utiliser var. Le problème n'est pas var; le problème vient des mauvais noms de variables. Si les noms de variables sont bien choisis, l'utilisation de var n'a pas d'importance.
Ryan Lundy le
J'ai un gars dans mon équipe qui examine son propre code et recherche des bogues en imprimant son code. Ses murs sont couverts de code. Je suis entré une fois et il avait un grand tableau blanc entier recouvert d'un seul de ses exercices de débogage. Il était probablement ~ 10000 LOC
Bip bip
Les noms de variables seuls ne résolvent pas le problème sauf si vous revenez à la notation hongroise où le type fait partie du nom.
Kevin Gale
17

Je ne vois pas ce qu'est le gros problème ..

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

Vous avez toujours l'intellisense complet sur «quelque chose», et pour tout cas ambigu, vous avez vos tests unitaires, non? ( le faites vous? )

Ce n'est pas varchar, ce n'est pas sombre et ce n'est certainement pas un typage dynamique ou faible. Il arrête maddnes comme ceci:

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

et réduire cet encombrement total à:

var v = new List<somethinglongtypename>();

Nice, pas tout à fait aussi agréable que:

v = List<somethinglongtypename>();

Mais c'est à ça que sert Boo .

Frep D-Oronge
la source
le type de "quelque chose" est très clair pour le compilateur, en interne, le "var" est défini sur le type de retour de "someMethod", il est clair pour le compilateur, mais peut ne pas être clair pour les développeurs travaillant sur le projet. et Boo grandit rapidement sur moi.
stephenbayer
Non, ce v = List<somethinglongtypename>();n'est pas encore mieux. Il est important de distinguer entre l'introduction d'une nouvelle variable et l'attribution à une variable existante.
HighCommander4
Eh bien, si vous avez déjà attribué à «v» dans la portée actuelle, il s'agit d'une affectation à un existant. Sinon, c'est l'affectation à la nouvelle variable «v». Facile.
Frep D-Oronge
17

Si quelqu'un utilise le varmot - clé parce qu'il ne veut pas "comprendre le type", c'est définitivement la mauvaise raison. levar mot-clé ne crée pas de variable avec un type dynamique, le compilateur doit encore connaître le type. Comme la variable a toujours un type spécifique, le type doit également être évident dans le code si possible.

Les bonnes raisons d'utiliser le varmot-clé sont par exemple:

  • Où cela est nécessaire, c'est-à-dire pour déclarer une référence pour un type anonyme.
  • Où cela rend le code plus lisible, c'est-à-dire en supprimant les déclarations répétitives.

L'écriture du type de données facilite souvent le suivi du code. Il montre quels types de données vous utilisez, afin que vous n'ayez pas à déterminer le type de données en déterminant d'abord ce que fait le code.

Guffa
la source
11

Étant donné la puissance d'Intellisense, je ne suis pas sûr que var soit plus difficile à lire que d'avoir des variables membres dans une classe ou des variables locales dans une méthode qui sont définies hors de la zone d'écran visible.

Si vous avez une ligne de code telle que

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

Est beaucoup plus facile ou plus difficile à lire que:

var nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();
Colin Desmond
la source
Je n'ai pas vraiment pris en compte cela, car il semble d'après l'autre question que c'est un point assez fort pour une autre fois de l'utiliser.
Finglas
C'est essentiellement la seule raison pour laquelle ils l'ont implémenté (en plus de pouvoir déclarer des types anonymes, mais ils auraient pu faire de "var" un mot-clé spécial qui n'était réservé qu'aux types anonymes.)
mqp
10

Je pense que l'élément clé avec VAR est de ne l'utiliser que lorsque cela est approprié, c'est-à-dire lorsque vous faites des choses dans Linq qu'il facilite (et probablement dans d'autres cas).

Si vous avez obtenu un type pour quelque chose dans l'alors vous devriez l' utiliser - ne pas le faire est simple paresse (par opposition à la paresse créative qui est généralement être encouragé - de bons programmeurs travaillent souvent très difficile d'être paresseux et pourrait être considéré comme la source de la chose en premier lieu).

Une interdiction générale est aussi mauvaise que d'abuser de la construction en premier lieu, mais il doit y avoir une norme de codage raisonnable.

L'autre chose à retenir est que ce ne est pas un type VB var en ce qu'elle ne peut pas changer de type - il est une variable fortement typé juste que le type est déduit ( ce qui explique pourquoi il y a des gens qui fait valoir que son pas déraisonnable de l'utiliser dans, disons, un foreach mais je ne suis pas d'accord pour des raisons de lisibilité et de maintenabilité).

Je soupçonne que celui-ci va fonctionner et fonctionner (-:

Murph

Murph
la source
10

Bien sûr, intc'est facile, mais lorsque le type de variable est IEnumerable<MyStupidLongNamedGenericClass<int, string>>, var rend les choses beaucoup plus faciles.

Blorgbeard est sorti
la source
2
+1 pour cela. intversus varest quelque chose à se chamailler, mais plusieurs types génériques imbriqués font varune aubaine. C'est là que l'utilisation répétée du nom de type détruit vraiment la lisibilité du code.
Chris Farmer
Ce n'est absolument pas la bonne raison de l'utiliser. Si votre code utilise un type générique imbriqué, vous devez en dériver une classe nommée spécifique. Par exemple: class IntStringEnumerator : IEnumerable<MyStupidLongNamedGenericClass<int, string>>puis utilisez le nouveau nom. Cela nettoie le code et décrit mieux le type.
xxbbcc
D'accord, mais mon exemple était juste une hyperbole. IntStringEnumerator i = new IntStringEnumerator()est encore trop de frappe.
Blorgbeard est sorti le
9

Volé de la poste sur ce problème à CodingHorror :


Malheureusement, vous et tout le monde vous êtes trompé. Bien que je convienne avec vous que la redondance n'est pas une bonne chose, la meilleure façon de résoudre ce problème aurait été de faire quelque chose comme ceci:

MyObject m = new ();

Ou si vous passez des paramètres:

Personne p = nouveau ("FirstName", "LastName);

Lors de la création d'un nouvel objet, le compilateur déduit le type du côté gauche et non du droit. Cela présente d'autres avantages par rapport à "var", dans la mesure où il pourrait également être utilisé dans les déclarations de champ (il existe également d'autres domaines qui pourraient être utiles, mais je ne vais pas y entrer ici).

En fin de compte, il n'était tout simplement pas destiné à réduire la redondance. Ne vous méprenez pas, "var" est TRÈS important en C # pour les types / projections anonymes, mais l'utilisation ici est tout de même OFF (et je le dis depuis longtemps, très longtemps) car vous obscurcissez le type qui est en train d'être utilisé. Devoir le taper deux fois est trop souvent, mais le déclarer zéro fois est trop peu.

Nicholas Paldino .NET / C # MVP le 20 juin 2008 08:00


Je suppose que si votre principale préoccupation est de devoir taper moins - il n'y a aucun argument qui vous empêchera de l'utiliser.

Si vous ne serez jamais que la personne qui regarde votre code, alors qui s'en soucie? Sinon, dans un cas comme celui-ci:

var people = Managers.People

ça va, mais dans un cas comme celui-ci:

var fc = Factory.Run();

il court-circuite toutes les déductions de type immédiates que mon cerveau pourrait commencer à former à partir de «l'anglais» du code.

Sinon, utilisez votre meilleur jugement et votre «courtoisie» de programmation envers les autres qui pourraient avoir à travailler sur votre projet.

Rostov
la source
4
Vos exemples ci-dessus ne sont pas un argument pour ne pas utiliser var; ils sont un argument pour utiliser de bons noms de variables descriptives. Si, au lieu de [var fc = Factory.Run ();] vous aviez [bool fc = Factory.Run ();], le code ne deviendrait pas plus clair.
Ryan Lundy
9

Utiliser varau lieu du type explicite rend les refactorisations beaucoup plus faciles (donc je dois contredire les affiches précédentes qui signifiaient que cela ne faisait aucune différence ou que c'était purement du "sucre syntaxique").

Vous pouvez modifier le type de retour de vos méthodes sans modifier chaque fichier dans lequel cette méthode est appelée. Imaginer

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

qui est utilisé comme

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

Si vous vouliez refactoriser SomeMethod()pour retourner un IEnumerable<MySecondClass>, vous devrez changer la déclaration de variable (également à l'intérieur duforeach ) à chaque endroit où vous avez utilisé la méthode.

Si vous écrivez

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

au lieu de cela, vous n'avez pas à le changer.

MartinStettner
la source
d'accord - se demandant pourquoi ce bel effet secondaire n'est pas autant vanté que certains des autres pros plus subjectifs dans les réponses les plus populaires.
fieldingmellish
Cela m'arrive aujourd'hui. J'ai une classe d'usine qui renvoie la distance d'une classe MainMenu. Aujourd'hui, j'ai créé un MainMenu2 avec la même interface que MainMenu. Je n'ai pas touché mon code d'application après le changement!
Marco Staffoli
8

@aku: Un exemple est les revues de code. Un autre exemple est la refactorisation de scénarios.

Fondamentalement, je ne veux pas aller à la chasse aux caractères avec ma souris. Il pourrait ne pas être disponible.

erlando
la source
2
C'est intéressant que vous disiez cela parce que var peut simplifier le refactoring. Si vous avez utilisé var, vous n'êtes pas obligé de le faire. Maintenant, vous pouvez toujours compter sur les outils de refactoring de l'IDE, mais vous savez, vous pouvez toujours compter sur l'IDE pour le type également :)
Fred
8

C'est une question de goût. Toutes ces histoires sur le type d'une variable disparaissent lorsque vous vous habituez à des langues typées dynamiquement. Autrement dit, si jamais vous commencez à les aimer (je ne sais pas si tout le monde peut le faire, mais je le fais).

C # varest plutôt cool en ce qu'il ressemble à une frappe dynamique, mais en fait c'est une frappe statique - le compilateur applique une utilisation correcte.

Le type de votre variable n'est pas vraiment important (cela a déjà été dit). Il doit être relativement clair d'après le contexte (ses interactions avec d'autres variables et méthodes) et son nom - ne vous attendez pas à ce que customerList contienne un int...

J'attends toujours de voir ce que mon patron pense de cette question - j'ai une couverture "allez-y" pour utiliser toutes les nouvelles constructions en 3.5, mais que ferons-nous de la maintenance?

Daren Thomas
la source
7

Dans votre comparaison entre IEnumerable<int>et IEnumerable<double>vous n'avez pas à vous inquiéter - si vous passez le mauvais type, votre code ne sera pas compilé de toute façon.

Il n'y a aucune inquiétude concernant la sécurité des caractères, car elle varn'est pas dynamique. C'est juste la magie du compilateur et tout type d'appels dangereux que vous effectuez sera pris.

Var est absolument nécessaire pour 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
    };

Maintenant, regardez anonEnumeration dans intellisense et il apparaîtra quelque chose commeIEnumerable<'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
}

Le compilateur C # est assez intelligent - les types anon générés séparément auront le même type généré si leurs propriétés correspondent.

En dehors de cela, tant que vous avez Intellisense, il est judicieux d'utiliser varpartout où le contexte est clair.

//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
la source
Veuillez vous débarrasser IQueriable<T>avant d'itérer: anonEnumeration.ToList();
David Diez
@DavidDiez pourriez-vous reformuler? Votre déclaration n'a aucun sens. Aucune de mes références d'extraits de code 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 };ne renvoie pas un IQueriable<T>?
David Diez
1
@DavidDiez cela dépend de ce qui AllPosts()retourne - le demandeur se réfère List<T>donc j'ai supposé cela. Dans ce cas, le résultat est anonEnumerationde type IEnumerable<'a>. Maintenant, si AllPosts()renvoie à la IQueryable<T>place, alors anonEnumerationdeviendra IQueryable<'a>(notez non idans Queryable) - cependant dans ce cas, mon code fonctionne toujours car il IQueryable<T>implémente IEnumerable<T>. Il y a beaucoup de meilleures questions et réponses sur les distinctions entre elles - ici, mon cas 'aest anonyme et varvous permet de l'assigner à une variable typée statiquement.
Keith
Ohh je vois, merci de l'expliquer :) Mon commentaire était parce que l'itération d'un IQueryable<T>n'est pas une bonne pratique car à chaque itération vous faites une instruction de lecture dans DB. Assurez-vous de bien *.ToList() IQueryable<T>les parcourir
David Diez
7

Je suppose que cela dépend de votre point de vue. Personnellement, je n'ai jamais eu de difficulté à comprendre un morceau de code à cause d'une var"mauvaise utilisation", et mes collègues et moi l'utilisons beaucoup partout. (Je conviens qu'Intellisense est une aide énorme à cet égard.) Je m'en réjouis comme moyen d'éliminer la cruauté répétitive.

Après tout, si des déclarations comme

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

étaient vraiment impossibles à gérer, personne n'utiliserait des langages typés dynamiquement.

mqp
la source
Vraisemblablement dans .Net 4 où les types dynamiques sont monnaie courante, cela deviendra plus important?
Colin Desmond
2
Au contraire, si vous êtes confus par "var" maintenant, je m'attendrais à ce que vous soyez en outre confus par "dynamique". Dieu nous en préserve, quiconque déclare une dynamique et y fait ensuite référence en utilisant "var" :)
mqp
Je voulais dire quelque chose comme dynamique d = 52; var x = d; ce qui devrait être bien.
mqp
7

J'utilise uniquement var quand il est clair de voir quel type est utilisé.

Par exemple, j'utiliserais var dans ce cas, car vous pouvez voir immédiatement que x sera du type "MyClass":

var x = new MyClass();

Je n'utiliserais PAS var dans des cas comme celui-ci, car vous devez faire glisser la souris sur le code et regarder l'info-bulle pour voir quel type renvoie MyFunction:

var x = MyClass.MyFunction();

Surtout, je n'utilise jamais var dans les cas où le côté droit n'est même pas une méthode, mais seulement une valeur:

var x = 5;

(parce que le compilateur ne peut pas savoir si je veux un octet, un court, un entier ou autre)

Christian Specht
la source
Si le côté droit n'est pas assez clair pour justifier l'utilisation de var, alors ce varn'est pas le problème: le côté droit est le problème. Ce n'est pas assez descriptif . Customer c = GetContext()n'est toujours pas clair et ne vaut pas mieux que d'utiliser var.
JulianR
6

Pour moi, l'antipathie envers varillustre pourquoi le bilinguisme dans .NET est important. Pour les programmeurs C # qui ont également fait VB .NET, les avantages de varsont intuitivement évidents. La déclaration C # standard de:

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

est l'équivalent, dans VB .NET, de taper ceci:

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

Cependant, personne ne fait cela dans VB .NET. Ce serait idiot, car depuis la première version de .NET, vous avez pu le faire ...

Dim whatever As New List(Of String)

... qui crée la variable et l'initialise en une seule ligne raisonnablement compacte. Ah, mais si tu veux un IList<string>, pas un List<string>? Eh bien, dans VB .NET, cela signifie que vous devez le faire:

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

Tout comme vous devriez le faire en C #, et ne pouvez évidemment pas l'utiliser varpour:

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

Si vous avez besoin que le type soit différent, cela peut l'être. Mais l'un des principes de base d'une bonne programmation est de réduire la redondance, et c'est exactement ce que fait var.

Ryan Lundy
la source
1
C'est drôle que vous mentionniez le bilinguisme comme quelque chose qui favorise l'utilisation de var. Mon antagonisme envers le mot-clé var découle directement de ma maîtrise de javascript! :)
urig
varen C # n'a aucune connexion avec varJavaScript. Une varvariable déclarée en C # est fortement typée.
Ryan Lundy
6

Utilisez-le pour les types anonymes - c'est pour ça qu'il est là. Tout le reste est une utilisation trop loin. Comme beaucoup de gens qui ont grandi sur C, j'ai l'habitude de regarder à gauche de la déclaration pour le type. Je ne regarde pas du côté droit, sauf si je dois le faire. Utiliser varpour toute ancienne déclaration me fait le faire tout le temps, ce que je trouve personnellement inconfortable.

Ceux qui disent «ça n'a pas d'importance, utilisez ce dont vous êtes satisfait» ne voient pas l'image entière. Tout le monde récupérera le code des autres à un moment ou à un autre et devra faire face à toutes les décisions qu'il aura prises au moment de l'écrire. C'est déjà assez dommage de devoir faire face à des conventions de dénomination radicalement différentes, ou - le reproche classique - à des styles de contreventement, sans ajouter le tout `` varou pas '' au mélange. Le pire des cas sera celui où un programmeur n'a pas utilisé var, puis vient un responsable qui l'aime et étend le code en l'utilisant. Alors maintenant, vous avez un désordre impie.

Les normes sont une bonne chose précisément parce qu'elles signifient que vous êtes beaucoup plus susceptible de pouvoir récupérer du code aléatoire et de le bloquer rapidement. Plus il y a de choses différentes, plus cela devient difficile. Et le passage au style «var partout» fait une grande différence.

Cela ne me dérange pas de taper dynamiquement, et cela ne me dérange pas de taper implicitement - dans des langues qui sont conçues pour eux. J'aime bien Python. Mais C # a été conçu comme un langage typiquement explicite et c'est ainsi qu'il devrait rester. Briser les règles pour les types anonymes était déjà assez mauvais; laisser les gens aller encore plus loin et briser encore plus les idiomes de la langue est quelque chose dont je ne suis pas satisfait. Maintenant que le génie est sorti de la bouteille, il n'y retournera plus jamais. C # deviendra balkanisé dans les camps. Pas bon.

Neil Hewitt
la source
7
Sensationnel. Ignorer tous les arguments avancés jusqu'ici dans ce fil et remettre en place toute la discussion est tout un exploit.
Konrad Rudolph
Ce 100% décrit ce que je ressens à propos de «var», en particulier du point de vue de la récupération du code de quelqu'un d'autre. L'utilisation de var change radicalement la tâche à accomplir si elle est jonchée partout. +1
Simon
6

Plusieurs fois pendant les tests, je me retrouve avec un code comme celui-ci:

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

Maintenant, parfois, je veux voir ce que contient SomeOtherThing lui-même, SomeOtherThing n'est pas du même type que celui renvoyé par CallMethod (). Puisque j'utilise var cependant, je change juste ceci:

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

pour ça:

var something = myObject.SomeProperty.SomeOtherThing;

Sans var, je devrais également changer le type déclaré sur le côté gauche. Je sais que c'est mineur, mais c'est extrêmement pratique.

BFree
la source
6

Pour les afficionados qui pensent var gagner du temps, il faut moins de touches pour taper:

StringBuilder sb = new StringBuilder();

que

var sb = new StringBuilder();

Comptez-les si vous ne me croyez pas ...

19 contre 21

Je vais vous expliquer si je dois le faire, mais essayez-le ... (selon l'état actuel de votre intellisense, vous devrez peut-être en taper deux de plus pour chacun)

Et c'est vrai pour tous les types auxquels vous pouvez penser !!

Mon sentiment personnel est que var ne doit jamais être utilisé sauf lorsque le type n'est pas connu car il réduit la reconnaissance en lecture dans le code. Il faut plus de temps au cerveau pour reconnaître le type qu'une ligne complète. Les anciens qui comprennent le code machine et les bits savent exactement de quoi je parle. Le cerveau traite en parallèle et lorsque vous utilisez var, vous le forcez à sérialiser son entrée. Pourquoi voudrait-on faire travailler son cerveau plus dur? C'est à ça que servent les ordinateurs.

Wray Smallwood
la source
Je trouve la répétition de stringBuilder sb = new StringBuilder () désordonnée et plus longue à reconnaître clairement. C'est du bruit supplémentaire. Le problème est que déterminer ce qui constitue et ne constitue pas un effort intellectuel supplémentaire pour comprendre un code est assez subjectif!
ljs
"var ne doit jamais être utilisé sauf si le type n'est pas connu ..." - Vous pouvez TOUJOURS connaître le type, tout comme le compilateur. Ce n'est pas du typage dynamique, cela permet simplement au compilateur de déterminer le type pour vous. Mais le type n'est jamais un inconnu.
Gabriel Magana
5

Je divisé var partout dans les lieux, les endroits que douteux pour moi sont des types internes courts, par exemple , je préfère int i = 3;plusvar i = 3;

robi-y
la source
5

Cela peut certainement simplifier les choses, à partir du code que j'ai écrit hier:

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

Cela aurait été extrêmement verbeux sans var.

Addendum: Un peu de temps passé avec un langage avec une inférence de type réel (par exemple F #) montrera à quel point les compilateurs sont bons pour obtenir le bon type d'expressions. Cela a certainement signifié que j'ai tendance à utiliser varautant que possible, et l'utilisation d'un type explicite indique maintenant que la variable n'est pas du type de l'expression d'initialisation.

Richard
la source
Oui, les compilateurs sont plus intelligents que nous, surmontez-le!
Benjol