Salut
Y a t il moyen d'eviter/alleger ce genre de code
Thx :yaisse2:Code:
1
2
3
4
5 if (a != null && a.b != null && a.b.c != null && a.b.c.d != null) { a.b.c.d.Test(); }
Version imprimable
Salut
Y a t il moyen d'eviter/alleger ce genre de code
Thx :yaisse2:Code:
1
2
3
4
5 if (a != null && a.b != null && a.b.c != null && a.b.c.d != null) { a.b.c.d.Test(); }
A ma connaissance, non.
Je mets une baffe au premier qui propose ça :;)Code:try{ a.b.c.d.Test(); } catch {}
c'est très laid comme code quand même :?
:nono: "Ne parlez pas aux inconnus - ne parlez qu'à vos amis immédiats"
Il faut être attentif pour chaque objet au nombre de classes avec lesquelles il interagit. Ce principe évitela création de classes fortement couplées.
Concrétement, si tu considères un objet; à partir de n'importe quelle méthode de cet objet tu ne dois appeler que des méthodes qui appartiennent:
Il faut éviter les a.GetObjet.GetObjet.GetObjet etc.
- à cet objet
- aux objets transmis en arguments à la méthode
- aux objets que la méthode crée
- aux composants de l'objet
Ici ton objet n'a des référence qu'à "a". Il ne doit donc pas connaitre b, c ou d. Si tu veux executer la méthode Test, demande le à "a" c'est tout. Et c'est "a" qui se chargera d'appeler b etc.
Code:
1
2
3
4
5 if (a != null) { a.AppelerTest(); }
Le Null object pattern est ce dont tu as besoin :) Google !
Exemple : (attention, bidouille, mais jolie bidouille :))
J'avais trouvé ça sur le net, je sais plus où. Sur CodeProject probablement.Code:
1
2
3
4
5
6
7
8
9
10
11
12 public class Address { private static Address Empty = new Address(); public string StreetName = null; public static Address operator +(Address address) { return address ?? Empty; } } Console.WriteLine("The street name is "+ (+address).StreetName ?? "n/a" + ".");
Encore un fana de ce genre de code, faut savoir que tout le monde ne comprends pas :DCode:return address ?? Empty;
Je ne comprends pas :D
Peux tu s'il te plait m'expliquer ce que font les ??
http://msdn2.microsoft.com/fr-fr/lib...24(VS.80).aspx
;)
Page très importante :
http://msdn2.microsoft.com/fr-fr/lib...5d(VS.80).aspx
Personnellement, je trouve cela particuliérement inélégant (pas tant la définition que la syntaxe d'appel (+address), mais on a le droit de le qualifier de "jolie bidouille"; en premiére lecture, et, en imaginant que je trouve cela dans un code, je le qualifierais plutôt d'inutilement abscon.
Pas forcement, pour une question de lisibilité et de maintenabilité je pense que l'utilisation de ?? n'est pas térrible.
Ecrire le test c'est mieux.
Ne me raconter pas que c'est une histoire d'optimisation, on ne gagne pas grand chose avec cela, et en dehors du monde de l'embarqué, ce n'est pas très utile.
je trouve que c'est plus un truc de codeur qu'autre chose.
Mais le codeur tend à disparaître :mrgreen:
Comme écrire en français sans faire de faute d'orthographe, de conjugaison, et de grammaire :mouarf:
Ce qui ne veut pas dire qu'il faut éradiquer cet usage au détriment du sens.
C'est incohérent, parce que selon ton raisonnement si tu veux appeler a.b.c.d.méthode tu dois implémenter a.appelMéthode->b.appelMéthode->c.appelMéthode->d.méthode, ce qui implique que c fait tout ce que fait d, b tout ce que fait c, et a fait tout ce que fait b, donc a connait le comportement de b, c et d ! Et d'un point de vue sémantique c'est une erreur car cela ajoute un comportement dans a qui n'a pas lieu d'être.Citation:
Ici ton objet n'a des référence qu'à "a". Il ne doit donc pas connaitre b, c ou d. Si tu veux executer la méthode Test, demande le à "a" c'est tout. Et c'est "a" qui se chargera d'appeler b etc.
Moi non plus j'utiliserai jamais ça dans un projet hein :)
Ce que je voulais montrer, c'est que le null pattern object pourrait être plus intégré au langage. Ca vous gonfle pas, vous, de devoir tester la nullité d'une référence avant d'effectuer une opération, alors qu'on voudrait simplement ne rien faire si l'objet est null ? Il serait intéressant d'avoir une syntaxe permettant d'indiquer simplement que faire quand une référence est nulle UNE BONNE FOIS POUR TOUTES plutôt que de faire des if (machin == null).
Par exemple :
L'idéal serait un "anti-nullable" : une notation pour des références qui ne peuvent pas être null. Ca nécessiterait de codifier la notion de "valeur par défaut", mais ça serait intéressant et virerait des tas de tests relous. Et le bout de code que j'ai filé dans mon précédent post n'est qu'une façon bidouillatrice de représenter le concept :)Code:
1
2
3
4
5
6
7
8
9
10 // bouh, bavard, j'aime pas ! foreach(Machin machin in listMachin) { if (machin != null) machin.Update(); } // mieux ! MachinNull machinparDefaut = new MachinNull(); // MachinNull hérite de Machin, avec une fonction Update qui fait rien foreach(Machin machin in listMachin) (machin ?? machinparDefaut).Update();
@ced600 : par contre, le ?? n'est pas une bidouille ni un délire d'esthète, il permet au contraire de clarifier le code... Va dire aux BDA que la coalescence sert à rien :)
Machin machin = GetMachinInCache(42) ?? GetMachinSurUnServeur(42);
est plus simple et plus lisible que
Machin machin = GetMachinInCache(42);
if (machin == null)
machin = GetMachinSurUnServeur(42);
M'en sers tout le temps.
C'est au contraire très cohérent. En fait, si on prend un exemple de la vraie vie, c'est plus simple à comprendre. Prenons une entreprise de peinture en batiment. Cette entreprise sait faire de la peinture en batiment parce que ses employés savent faire de la peinture en batiment.
Un client va embaucher la société car il sait que celle-ci dans sa globalité sait faire de la peinture en batiment. Ce client se fiche de savoir si c'est Néness ou Dédé qui sait peindre. Il ne voit que la société.
Pour revenir à notre exemple, la société de peinture serait la classe A qui contient/emploie des peintres B qui savent peindre (méthode appelée).
Au final, la classe utilisatrice (celle qui fait le if) ne devrait faire que A.méthode(). Après, peu lui importe que ce soit B ou C ou D qui peigne (appelle la méthode).
Je vais quand même donner mon avis sur ce code :
C'est pas très beau certes, mais en plus ça ne devrait pas exister.Code:
1
2
3
4
5 if (a != null && a.b != null && a.b.c != null && a.b.c.d != null) { a.b.c.d.Test(); }
Soit b, c et d sont passés en paramètres dans le constructeur de a, et dans ce cas si il y a un null, tu ne peux t'en prendre qu'à toi-même. Sous-entendu que c'est bien avant que le test doit s'effectuer, pas sur l'appel.
Soit b, c et d sont entièrement à la charge de a, et tu devrais te manger une exception directement à l'instanciation de a si quelque chose cloche pour charger b, c et d !
Devoir tester un tel arbre d'appel ça a une bonne tête d'anti-pattern quand même :mrgreen:
Je suis d'accord avec tout ce qui viens de ce dire.
D'ailleurs un exemple simple l'utilisation du patron de conception état pour un langage de programmation objet.
Lorsque tu veux gérer les états de ta classe, tu vas créer une classe d'état abstraite et faire faire plein de classe dérivé de celle-ci qui représente les états.
Ta classe de départ se fou royalement de savoir s'il elle va appellé la méthode de telle ou telle état, après il y une variable et une méthode qui s'occupe de gérer l'état courant.
Ta classe de départ appel la méthode de la classe abstraite.
Ce genre d'encapsulation te permet de faire des choses beaucoup plus fine, c'est plus lisible, et plus facilement maintenable.
@ Guulh :
je ne vois aps en koi c plus simple et plus lisible, je dirais même l'inverse.Code:
1
2
3
4
5
6
7 Machin machin = GetMachinInCache(42) ?? GetMachinSurUnServeur(42); est plus simple et plus lisible que Machin machin = GetMachinInCache(42); if (machin == null) machin = GetMachinSurUnServeur(42);
C'est comme tout ce qui est hérité du langage c++, les i++ i+=3, ...
C'est moins lisible, on si fait à force car on les rencontre tout le temps et on les utilise.
Mais ce genre de syntaxe n'est pas utilisé de la même façon partout, alors n'est pas facilement maintenable partout.
Et puis désolé mais : i = i +1 -> clair et compréhensible dès la première fois que tu le vois.
i++ -> lorsque tu le vois pour la première fois tu ne le comprends qu'après que l'on t'ai dit ue c'est la même chose que i = i + 1 !!!!!
AMHA, c'est comme beaucoup de choses produisant in fine le meme effet, à savoir une question de gout. ??, ca reste quand meme tres 'Geek-code', j'ai du le rencontrer une fois dans une source, alors que les operateurs d'incrementation, c'est quand meme globalement tres utilisé. C'est un peu pareil pour les operateurs ternaires, les methodes anonymes etc , certains trouvent ca clair, d'autres pas, toujours la meme chose, affaire de gout. =)
1) C'est pas la même chose d'un point de vue processeur, incrémenter va nettement plus vite, même si nous on s'en fout parce que les compilos unpoil optimisés remplacent automatiquement i = i+1 en i++.
2) T'abuses quand même, tu le vois une fois, tu l'apprends et c'est bon... C'est dans les 3/4 des langages. Je sais pas si t'as déjà fait du C++, mais avec les surcharges d'opérateurs de partout, tu prendrais peur :)
3) monIcone = estContent ? "Content.ico" : "pasContent.ico", je trouve ça clair et élégant. Les blocs if then else sont tellement courants qu'il se conçoit très bien d'en simplifier la syntaxe pour les cas les plus simples. :roll:
Pingouins ? Tu sais, grâce à Mono même les linuxiens ont accès à .Net :)
Les structs répondent à un certain nombre de besoins, mais sont trop différentes des classes, nécessitent une syntaxe lourde pour être passées en référence, n'autorisent pas l'héritage... Suffit de voir le faible usage qu'en fait le framework.
J'ai commencé par apprendre le c, puis le c++ (ensuite java et .net)Citation:
2) T'abuses quand même, tu le vois une fois, tu l'apprends et c'est bon... C'est dans les 3/4 des langages. Je sais pas si t'as déjà fait du C++, mais avec les surcharges d'opérateurs de partout, tu prendrais peur
J'ai comemencer à avoir peur en c lorsque certain faisait tenir en une ligne de code 5 lignes de code.
En c++ je n'ai jamais trop fait de la surcharge d'opérateurs, mais je conçoit qu'en abuser peut être inquiétant.
Bref tout cela rend la maintenance difficile.
Vous allez me dire que c'est comme les noms de variables : Certain prèfère V1, V2, V3, ... un choix comme un autre et d'autre des nom clair pour chaque variable, et certain des phrases comme nom de variable (ils abusent de la complétion propose par l'editeur)
Mais bon qu'en tu arrives à V50 en nom de variable, tu ne comprends plus rien au code. Je ne l'ai pas vécu mais quelqu'un qui l'a vécu me l'a raconté. Il était très enchanté de maintenir un tel code .... Il n'a rien compris a code et à tout réécrit, cela prenais moins de temps.
je reprendrai cette phrase :Citation:
3) monIcone = estContent ? "Content.ico" : "pasContent.ico", je trouve ça clair et élégant. Les blocs if then else sont tellement courants qu'il se conçoit très bien d'en simplifier la syntaxe pour les cas les plus simples.
Néanmoins si l'on veut être profesionnelle, il vaut mieux penser à la maintenance du code, que l'on ne fera pas forcement nous même.Citation:
C'est un peu pareil pour les operateurs ternaires, les methodes anonymes etc , certains trouvent ca clair, d'autres pas, toujours la meme chose, affaire de gout. =)
C'est comme pour les tests, beaucoup de boite ne font pas bcp de test, faute de temps. Cela alourdi la maintenance qui revient très couteuse.
Je peux vous dire que lorsqu'elles ont décrochés le contrat pour se soft avec inclus dedans la phase de maintenance, elles peuvent perdre de l'argent.
Celles qui ont compris cela effectue des tests plus appronfondis pour limiter cette maintenance.
Les structs en c# exitent uniquement pour jouer le rôle d'instance de classe dont nous n'avons pas besoin de conserver les données des arguments jusqu'à l'arret de l'application.
Cela évite de gacher de la mémoire pour des objets qui ne sont utilisés que sur une phase précise de l'application.
Je suis d'accord avec toi que des lignes comme "while (*p++ = *q++);"(si je me souviens bien) sont trop cryptiques. Je suis d'accord aussi que chaque développeur a ses goûts, et c'est pour cela qu'il est possible de faire la même chose de n façons différentes toutes aussi valables les unes que les autres (en C++ notamment :)).
Mais je ne pense pas que ce soit une raison suffisante pour niveller par le bas son code. A la limite si il doit être maintenu ponctuellement par quelqu'un dont le C# n'est pas la spécialité. Mais bon quand on choisit un outil (en l'occurence un langage de programmation), c'est aussi pour tirer profit de ses caractéristiques. Je n'ai pas de position rigide sur le sujet, ça se discute et ça dépend entièrement des projets (mais on s'éloigne un chouïa du sujet initial du thread là, désolé Seth77 :mrgreen:)
Ce n'est pas grave ce genre de discussion est importante, et montre un manque flagrant dans l'hamonisation des règles de codage.
Mais je ne pense pas que :
soit d'un plus bas niveau que :Code:i = i + 1
La seule vraie raison qui rend i++ plus intéressant que i = i +1 a été donné et c'est le cas où le compilo n'est pas optimisé.Code:i++
Pour ce qui ont fait du c++ je ne critique aps ++i qui apporte un fonctionnement différent de i++ .
Le problème vas être la mise en production des outils développés.
Ce qui intervienne sur ces outils en production, ils vont corriger en live le code, recompiler et redéployer.
Donc une maintenance super rapide doit être faite. Imagine toi que ces personnes est un jour du :
ou du :Code:while (*p++ = *q++);
Ils n'est pas forcément simple de switcher de l'un à l'autre rapidement.Code:// L'équivalent de while (*p++ = *q++) en développé, moi je ne sais pas faire cela
C'est pour cela que le code est "homogénéiser" avant de passer en production, on appelle cela une phase d'industrialisation.
Et le coût de cette industrialisation dépend de l'état du code s'il est proche d'un code industrielle.
Normalement durant cette phase tous les truc que permet le c++, toutes les contractions, bah on les vire ....
le code doit être simple à lire et rapide.
Bref tout cela pour dire que tu travailles rarement pour toi mais en général pour quelqu'un d'autre. Et donc il faut se mettre dans la peau de cette personne et imaginer ce qu'elle attend, que cela soit au niveau code, architecture, fonctionnalité du produit, IHM, ....
Je ne suis pas d'accord. Le verbe "incrémenter" existe, c'est pourquoi quand je parle je dis pas "j'ajoute 1", je dis "j'incrémente". Là, c'est pareil :) Tu écris pas for(int i = 0 ; i < n ; i = i +1), non ?
Certes, écrire du code qui ne reprend que ce qui est commun à c/C++/java/C# le rendra plus lisible par plus de gens. C'est une raison pour se passer du foreach parce que java le connait pas ? Des delegates, des event, de remoting parce que c'est propre à .Net ? Des templates/generics parce que y'a pas en C ? Et puis les syntaxes "propriétaires" ne sont pas forcément compliquées à comprendre. ??, c'est pas énorme, quand même.
Donc : ça dépend des projets, et même des modules. Parfois, on favorise la perf pure (bibliothèque de flux financiers, etc.), parfois la relecture facile, parfois l'utilsation du moins de bibliothèques externes possibles, etc.
Je ne pensais pas qu'une entité null pouvait soulever autant de remous codeurien :mrgreen:
Ne disons pas n'importe koi, lorsque l'on deve en un langage on ne se passe pas de ce qu'il propose c'est stupide.
Mais il y a les fénéantises du codeur qui pour ne pas fair 5 lignes va utiliser des simplifications qui rendent le code illisible, et il y a des besoins de clarté et de lisibilités sur les sources.
De toute façon tout cela disparaitra. On se tourne de plus en plus vers un monde où l'on aura des outils pour faire la conception et l'architecture, et c'est le logiciel, personnalisé pour les besoins de l'entrprise, qui développera le code.
De toutes façons sur les programmes simples actuellement ce genre de programmes codent mieux que nous. Et de plus en plus ils sont capables de générer un code de cette qualité pour des programmes plus complexe tant qu'on les guides en conception.
Bon c'est un autre débat et tout le monde n'est pas d'accord avec moi la dessus (heureusement sinon on s'ennuirais :D )
On est globalement d'accord :)
Mais je ne pense pas que ces syntaxes allégées soient de la fainéantise. Maîtrisées, elles facilitent la lisibilité du code. Comme par exemple les fonctions lambda proposées par l'imminent c# 3.0. Le tout est de pas en abuser bien sûr.
Et pour revenir au sujet principal du thread : supposons que dans une grille de clients à sélection par cellule, je veuille récupérer la ville du client de la cellule sélectionnée :
((sender as dataGridView).SelectedCells[0].OwningRow.DataBoundItem as Client).Ville
Bon j'ai exagéré en faisant tout tenir en une ligne :), mais c'est le genre de situation où on veut renvoyer null quand l'une des propriétés enchaînées est nulle (pas de cell sélectionnée, pas d'objet métier attaché, etc.). Ca serait pratique si il y avait un moyen syntaxique d'assurer qu'une propriété d'un objet n'est jamais nulle, comme par exemple la propriété Rows de DataGridView.
On est d'accord sur pas mal de points, sauf sur la lisibilité qu'apporte ces syntaxes, mais arrêtons de polémiquer la dessus :D
Lors d'un développement correct un attribut d'objet n'est accessible que par sa propriété, et celle-ci peu tester la nullité de la propriété après affectation.Citation:
Ca serait pratique si il y avait un moyen syntaxique d'assurer qu'une propriété d'un objet n'est jamais nulle, comme par exemple la propriété Rows de DataGridView.
Si tu associe à la propriété un booleen pour la nullité, dont tu affecte la valeur par la propriété de ton attribus, tu peux simplifier les choses pour l'utilisateur de l'objet.
Ainsi l'utilisation de la propriété peut se faire ainsi :
Par contre l'objet contiens plus d'attribut, et c'est un peu plus lourd pour le construire, mais avec une bonne dénommination de tes attributs, cela reste assez bien maintenable.Code:
1
2
3
4 If (MyObject.MyPropertyIsNotNull) { MyObject.MyProperty = .... ; }
Maintenant si C# propose l'équivalent je ne suis pas au courant.
Bon ok je suis un peu bète, ce serait moins gouramand de faire :
Mais bon j'aime bien réinventer le roue.Code:
1
2
3
4 If (MyObject.MyProperty != null) { MyObject.MyProperty = .... ; }
Mais qu'elle est le problème de faire un telle test ?
Franchement est ce si chiant que cela ?
Ce serais comme dire que fermer un stream c'est lourd, qu'on l'oublie tout le temps et qu'il faudrait qu'ils soient fermer automatiquement.
Ou je ne sais encore koi d'autre.
Mais tu auras quelqu'un qui va arriver et qui te diras ouais mais c mieux de laisser la liberteé pour patati et patata.
Bref un langage est telle qui l'est, il faut l'utiliser comme il est ou en cahnge, ou faire le siens (bon courage pour le compilateur :D )
Le mieux que l'on puisse faire est de définir la meilleur façon de coder avec pour telle ou telle situation avec telle ou telle objectif.
Non, ce n'est pas chiant de faire ce test, c'est juste que j'ai vu pas mal de projets bourrés de tests de nullité le plus souvent inutiles, et j'aime pas le code avec 15 niveaux d'indentation :mrgreen:
Il y a des propriétés des objets du framework qui ne sont JAMAIS nulles. Notamment les propriétés de type collection, qui sont quasiment toujours vides à la création de l'objet, mais pas nulles. Cette non-nullité pourrait être indiquée à l'utilisateur de la classe d'une façon ou d'une autre, ça serait pratique.
J'ai jamais dit le contraire:)
Bon, je résume :
.Net1 => séparation entre struct (type valeur, jamais null, passé par valeur aux fonctions avec possibilité de passage par référence grâce au mot clé "ref") et class (type référence, peut être null, toujours passé par référence).
.Net2 => ajout d'une syntaxe permettant de traîter une struct comme une class via les nullable (bien que Nullable<T> soit une struct, d'ailleurs)
un jour ? => possibilité de traîter une classe comme une struct du point de vue du rapport à la nullité sans devenir pour autant des types valeur.