IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Variable créée avec "var". Comment ça marche au juste ?


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut Variable créée avec "var". Comment ça marche au juste ?
    Bonjour,

    Je suis plutôt "old school" en ce qui concerne la déclaration et le typage des données.

    Donc moi je suis resté à l'époque où on déclarait une variable de cette façon :

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MyClass myinstance = new MyClass(parameters);

    Et donc, quand ma variable doit être une propriété :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class MyClass
    {
       AnotherClass myproperty;
     
       void SomeMethod()
       {
           myproperty = new AnotherClass(parameters);
       }
    }

    Sauf que là, les temps changes, et poussent comme des champignons des déclarations que je pensais presque avoir compris, mais qui finalement m'échappent totalement.

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var service = new CalendarService(new BaseClientService.Initializer()
    {
       HttpClientInitializer = credential,
       ApplicationName = myname,
    });

    Je sais pas comment, mais ça marche. Ma variable "service" me semble non typée (ça ressemble vachement à la déclaration javascript par exemple).

    Et là, j'ai un cas où...
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    class MyClass
    {
       private CalendarService service;
     
       void SomeMethod()
       {
          var service = new CalendarService(new BaseClientService.Initializer()
          {
             HttpClientInitializer = credential,
             ApplicationName = myname,
          });
       }
     
       void AnotherMethod()
       {
          service.DoSomething();
       }
    }

    Et le joli message :
    Warning 9 Field 'MyClass.service' is never assigned to, and will always have its default value null

    Qu'est-ce que je fois faire pour corriger le problème ?
    Car du coup, j'imagine que ma méthode "AnotherMethod" ne va jamais fonctionner...

  2. #2
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Hmmm, en relisant la documentation, j'ai un méchant doute...

    http://msdn.microsoft.com/en-us/library/bb383973.aspx

    En fait, si je comprends bien, du moment que j'ai pas une déclaration à la mords-moi-le-noeud de type anonyme, je connais déjà le type au moment de l'écriture du code.

    Du coup, si je vire simplement le mot-clé "var", ça corrige bien le problème ?

    Pas d'effet de bord caché ?

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    class MyClass
    {
       private CalendarService service;
     
       void SomeMethod()
       {
          service = new CalendarService(new BaseClientService.Initializer()
          {
             HttpClientInitializer = credential,
             ApplicationName = myname,
          });
       }
     
       void AnotherMethod()
       {
          service.DoSomething();
       }
    }

    En tout cas, maintenant ça compile sans warning...

    J'ai bon ?

  3. #3
    Membre très actif
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2007
    Messages
    871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Février 2007
    Messages : 871
    Par défaut
    Salut,

    T'as tout compris mais oublié un détail:

    le mot clé "var" est un "sucre" syntaxique au même titre que "Property" et sert juste à faire beau et ne pas retaper deux fois le type lorsque tu déclare et initialise une variable.

    En fait, si je comprends bien, du moment que j'ai pas une déclaration à la mords-moi-le-noeud de type anonyme, je connais déjà le type au moment de l'écriture du code.
    Tout à fait, d'ailleurs tu ne peux utiliser var que lorsque, sur la meme ligne tu créé ta variable et l'assigne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class MyClass
    {
       private CalendarService service;
     
       void SomeMethod()
       {
          var service = new CalendarService(new BaseClientService.Initializer()
          {
             HttpClientInitializer = credential,
             ApplicationName = myname,
          });
       }
    Dans le code ci dessus, tu crée un champ "service", non renseigné, que tu veux assigner dans "SomeMethod". Mais le fait d'utiliser "var service = new CalendarService(new BaseClie..." indique que ce n'est pas le champ de ta classe que tu rempli mais une nouvelle variable locale d'ou le warning du compilateur.
    Tu aurais le meme problème si tu avais écrit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CalendarService  service = new CalendarService(new BaseClientService.Initializer()...
    Voila, tout simplement.

  4. #4
    Membre Expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net Architect
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Par défaut
    Vu que tu as un champ appellé "service" au niveau de ta classe, si tu ajoutes "var" devant dans ta méthode, ce n'est plus une assignation à ce champ, mais une déclaration et assignation d'une nouvelle variable locale appellée aussi "service".
    Ce qui explique le warning

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    En fait, le mot clé "var" revient à dire "le type de l'initialisation de la variable".

    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    var fs = new FileStream("MonFichier.txt",FileMode.Open);
    //Equivaut exactement à cette déclaration :
    FileStream fs = new FileStream("MonFichier.txt",FileMode.Open);
    ou encore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    var fs = File.Open("MonFichier.txt",FileMode.Open);
    //Equivaut exactement à cette déclaration :
    FileStream fs = File.Open("MonFichier.txt",FileMode.Open);
    Pour aller plus loin, si tu as une fonction ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Stream GetAStream()
    {
       return File.Open("MonFichier.txt", FileMode.Open);
    }
    Alors dans ce cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    var fs = GetAStream();
    //Equivaut exactement à :
    Stream fs = GetAStream();
    "var" est traduit à la compilation.

    Le principal intérêt de "var" est pour les types anonymes en effet, car sans le "var", il n'y a aucun moyen de refaire référence au type anonyme.
    Les types anonymes sont utilisés à fond comme "types intermédiaires" dans les requêtes Linq.

    Par exemple, la requête Linq suivante va implicitement créer un type anonyme intermédiaire sans que tu ne le voies :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    DirectoryInfo dir = MonDossier();
    IEnumerable<FileInfo> mesFichiers =
    from f in dir.EnumerateFiles()
    let fileSize = f.Length
    where fileSize >= 50 && fileSize <= 500
    select f;
    Cette requête Linq me permet de trouver tous les fichiers dans mon dossier renvoyé par la fonction "MesDossiers()" qui ont une taille comprise entre 50 octets et 500 octets.

    Dans cette requête Linq, j'ai mis un "let" pour mémoriser la longueur du fichier actu pour ne pas rappeler la propriété "Length" dans le test, au cas où celle-ci serait un peu couteuse. Du coup, derrière, ça s'est traduit par un type anonyme intermédiaire.

    L'équivalent de cette requête Linq est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    IEnumerable<FileInfo> mesFichiers =
     dir.EnumerateFiles
     .Select(f => new { Source = f, fileSize = f.Length }) //Création du type anonyme intermédiaire
     .Where(o => o.fileSize >= 50 && o.fileSize <= 500) //Du coup, dans la lambda expression d'ici, la référence est celle du type anonyme
     .Select(o => o.Source);
    et donc à la fin, tu n'as plus de trace du type anonyme intermédiaire dans la visu code, mais si tu décompiles l'assemblage, tu le verras bien.

    Bon, alors là je suis un peu sorti du sujet "var" mais l'apparition des types anonymes est l'explication principale de l'apparition du mot clé "var".

    [EDIT] Merci Mickael. Au passage, j'ai corrigé une petite erreur que j'avais fais dans mon post.
    Dernière modification par Invité ; 05/06/2014 à 11h53.

  6. #6
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Juste pour compléter un peu l'explication de Philippe qui est excellente (+1) : l'autre cas d'utilisation de var c'est pour raccourcir certaines déclarations qui deviennent très longues avec du LINQ, typiquement le GroupBy où tu te retrouves avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IEnumerable< IGrouping < TKey, TSource > >
    Pour peu que ton TSource soit lui même un IDictionary<TKey, TValue> ça devient compliqué avec la moitié de la ligne consacrée à l'écriture du type.

    Mais en effet la raison fondamentale qui à elle seule explique var c'est l'ajout des types anonymes.

    En dehors de ces deux cas je déconseille très fortement l'usage de var qui obfusque le code en masquant l'information de typage qui est fondamentale : pas seulement à des fins de vérification par le compilateur mais aussi et surtout en tant que documentation pour les développeurs.

    Et les développeurs sans assez de recul et de maturité qui y goûtent on tendance à l'utiliser partout.
    Je vois régulièrement ce genre de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (var i = 0; i < n; ++i)
    Et c'est clairement n'importe quoi, on ne gagne même pas un caractère, on a juste obfusqué le code. :/

  7. #7
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Pragmateek Voir le message
    Et les développeurs sans assez de recul et de maturité qui y goûtent on tendance à l'utiliser partout.
    Je vois régulièrement ce genre de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (var i = 0; i < n; ++i)
    Et c'est clairement n'importe quoi, on ne gagne même pas un caractère, on a juste obfusqué le code. :/
    Je ne suis pas d'accord avec toi, et je ne vois pas quel est lien avec la maturité. Ceci pour deux raisons :
    1. Si on est pas capable de savoir que dans ce cas i sera de type int, alors y'a quand même un souci
    2. Ca ne change rien, puisque qu'on mette explicitement int ou var on utilise le même nombre de lettres, et au-delà de cet argument que certains qualifieront de futile, on se retrouve bien avec un type int au final. C'est juste une question de préférence personnelle

    Sur le projet sur lequel je bosse actuellement, nous avons beaucoup de généricité, donc on se retrouve parfois avec des appels du genre (j'ai mis n'importe quoi, c'est juste pour l'exemple) :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    IGenericObject<MaClasseA, IDictionary<MaClasseB, MaClasseC>> myVariable1 = new IGenericObject<MaClasseA, IDictionary<MaClasseB, MaClasseC>>();
    Ca prend déjà la moitié de la ligne ! Et en plus si on en a plusieurs d'affilé, c'est pas très sexy visuellement :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    IGenericObject<MaClasseA, IDictionary<MaClasseB, MaClasseC>> myVariable1 = new IGenericObject<MaClasseA, IDictionary<MaClasseB, MaClasseC>>();
    IEnumerable<IDictionary<MaClasseA, MaClasseB>> myVariable2 = new IEnumerable<IDictionary<MaClasseA, MaClasseB>>();
    IEnumerable<IEnumerable<IDictionary<MaClasseA, IDictionary<MaClasseB, MaClasseC>>>> myVariable3 = new IEnumerable<IEnumerable<IDictionary<MaClasseA, IDictionary<MaClasseB, MaClasseC>>>>();
    Personnellement, je pense qu'il vaut mieux avoir un truc un peu plus lisible, et qui donne le même résultat :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var myVariable1 = new IGenericObject<MaClasseA, IDictionary<MaClasseB, MaClasseC>>();
    var myVariable2 = new IEnumerable<IDictionary<MaClasseA, MaClasseB>>();
    var myVariable3 = new IEnumerable<IEnumerable<IDictionary<MaClasseA, IDictionary<MaClasseB, MaClasseC>>>>();
    Surtout qu'il suffit de survoler la variable pour connaître son type en cas de doute.

    Mais bon encore une fois, c'est une question de préférence et éventuellement de norme de codage définie sur un projet. Au final, ça revient strictement au même.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo