Bonjour, j'étais entrain de lire le tutoriel C# suivant: https://openclassrooms.com/courses/programmez-en-oriente-objet-avec-c/manipulez-des-objets
et j'ai été surpris par le fait qu'il n'y a aucune mention de l'encapsulation. Tous les attributs sont public et ils sont modifié sans utiliser d'accesseurs (Par exemple voitureNicolas.Vitesse = 50; depuis le corps du Main).
Ayant déjà programmé en C++ j'ai trouvé ça déroutant, l'encapsulation n'est pas aussi "importante" en C# que dans d'autres langages objets?
En C++ et en C#, un champ public, c'est exceptionnel, mais un simple accesseur "d'encapsulation", ça devrait même pas exister.
Qu’est-ce que tu appelles un "un accesseur d’encapsulation" ?
Pour moi c’est soit ça :
private float _poids;
public float GetPoids()
{
return _poids;
}
Soit ça :
private float _poids;
public float Poids => _poids;
Soit le get et le set d'une propriété :
public float Poids { get; private set; }
Et à priori ces trois bout de code génèrent à peu de chose près la même chose (du côté de l'IL j'entends). Du coup lorsque tu dis qu'une "encapsulation à base d'accesseurs, c'est bien plus mauvais que des champs publics", c'est une assertion qui englobe toutes les syntaxes ci-dessus, ou simplement le fait d'écrire une méthode pour accéder à un champs de stockage (comme c'est fait en Java il me semble) ?
Pour ma part ça me viendrait pas à l'esprit d'exposer directement un champ, je passerais systématiquement par une propriété, du coup je suis curieux.
Pour une structure qui expose des coordonnées 2D ou 3D, vas-tu faire de propriété GetX, GetY, Get Z ???
Si tu lis entièrement la phrase que j'ai écrite et que tu as coupée, je dis "ça ne me viendrait pas à l'esprit d'exposer directement un champ, je passerais systématiquement par une propriété".
Donc évidement que non je ne vais pas me farcir l'écriture de ces méthodes... J'aurais 3 propriétés X, Y et Z et prendrais soin de restreindre l'accès au set de chacune d'entre-elles de sorte à garantir le caractère immutable de mon type..
Mais encore une fois, les propriétés ne sont que du sucre syntaxique ; derrière ce sont bien des méthodes du type GetUnTruc, SetUnTruc qui sont générées. Ma question c'était de savoir ce que tu condamnais au final ; le fait d'écrire ces méthodes à la main, ou bien l'encapsulation dans sa globalité ?
Pourquoi tant de why outrés, c’est toi qui me parle de struct ; vu qu’on a affaire à un type valeur, il y a fort à parier que -au moins par convention- on va rendre ce type immuable. Ce n’est pas une obligation, certes, mais si on ne le fait pas on se retrouve avec le risque de modifier de malheureuses copies d’objets éphémères.
Bon, mais toute digression mise à part, une propriété face à un simple champ public va avoir l’avantage d’être implémentable via une interface, d’être potentiellement surchargeable dans les classes enfants, en WPF ça va permettre de faire du binding, et j’en passe...
Je ne vois absolument aucun avantage au champ public, uniquement du danger potentiel. Et je ne vois absolument pas pourquoi on ne pourrait pas systématiser l’utilisation des propriétés, même pour des membres accessibles en lecture et en écriture.
Si c’est pour gagner sur le plan performance, j’appelle ça « sodomiser des acariens au nanotube » ...
(Au passage, je te mets au défi d’ouvrir une classe du Framework .net, au pif, et d’y trouver des champs publics)
Si c’est pour gagner sur le plan performance, j’appelle ça « sodomiser des acariens au nanotube » ...
Bah surtout qu'à priori le compilo inline les propriétés simples (sans code spécifique)
Pour en revenir à la question de base
Jarka a écrit:
Bonjour, j'étais entrain de lire le tutoriel C# suivant: https://openclassrooms.com/courses/programmez-en-oriente-objet-avec-c/manipulez-des-objets
et j'ai été surpris par le fait qu'il n'y a aucune mention de l'encapsulation. Tous les attributs sont public et ils sont modifié sans utiliser d'accesseurs (Par exemple voitureNicolas.Vitesse = 50; depuis le corps du Main).
Vitesse n'est pas un champ (champ C# = attribut C++/Java), mais une propriété. Une propriété est un ensemble de 2 méthodes (get et set), mais s'utilise comme un champ (ce qui est évidemment plus pratique). Donc tu as bien ton encapsulation ici. C'est juste que l'écriture est simplifiée (on appelle ça les propriétés auto-implémentées).
public MonType MaPropriété { get; set; }
est l'équivalent de :
private MonType _monChampNonVisible;
public MonType MaPropriété
{
get { return _monChampNonVisible; }
set { _monChampNonVisible = value; }
}
Aux lignes 5 et 6, tu peux écrire le code que tu veux, les vérifications que tu veux, les notifications que tu veux. Dans l'exemple que je donne la propriété est publique. Le getter et le setter sont publiques. On peut changer la visibilité de la propriété. On peut également modifier la visibilité du getter OU du setter en mettant le modificateur de visibilité juste devant le get ou le set, à condition que cette visibilité soit nécessairement plus restrictive que la visibilité globale de la propriété.
public MonType MaPropriété
{
get { return _monChampNonVisible; }
private set { _monChampNonVisible = value; }
}
Là, le getter est public et le setter est privé.
Voici la liste exhaustive des relations entre visibilité.
public > internal protected
public > internal
public > protected
public > private
internal protected > internal
internal protected > protected
internal protected > private
internal > private
protected > private
Il est donc impossible d'avoir une propriété dont le getter est internal et le setter protected ou vice-versa.
Il y a 2 types de personnes : celles qui sont capables d'extrapoler à partir de données incomplètes.
>Bah surtout qu'à priori le compilo inline les propriétés simples (sans code spécifique)
Ce qui justifie mon aversion à ce décorum totalement inutile.
Si on met en place une propriété, c'est pour la concevoir en tant que tel, et pas une simple bidouille pour dire "moi, je fais de l'encapsulation avec des getter/setter".
C'est du bullsheet s'il n'y pas de conception derrière.
> il y a fort à parier que -au moins par convention- on va rendre ce type immuable
Why ???
Si je veux un DTO avec 2 int, pourquoi chercher à sur-concevoir le truc ?
>en WPF ça va permettre de faire du binding, et j’en passe...
Cela implique une conception, et mettre des champs dans des propriétés, ce n'est pas une conception !
>aucun avantage au champ public, uniquement du danger potentiel
Parce que tu veux faire plus avec quelque chose qui n'a pas été CONÇU pour. Ce que je dis et redis, c'est qu'il faut concevoir les propriétés, comme le reste. Pour un DTO, la conception, c'est vite vue. => over-engineering.
>« sodomiser des acariens au nanotube »
Je te retourne la formule.
>(Au passage, je te mets au défi d’ouvrir une classe du Framework .net, au pif, et d’y trouver des champs publics)
>Bah surtout qu'à priori le compilo inline les propriétés simples (sans code spécifique)
Je crois que c'est vite vue.
Le seul vrai message, c'est de concevoir correctement vos API et que l'utilisation de getter/mutater, C'EST PAS DE LA CONCEPTION, C'EST NIMPORNAWAK.
Si après conception, j'ai un objet type DTO, je m'en cogne des getters/mutaters tout moisi.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Balade-toi dans le repo à la recherche d’une classe ou d’une structure -quel que soit la finalité du type- qui exposerait un champ public. J’attends tes trouvailles.
Bon après c’est peut-être les mecs de chez Crosoft qui codent comme des mulets. Dans ce cas c’est con ; ce sont eux qui pondent les guidelines du langage.
Bref, on ne sera jamais d’accord sur ce sujet. Du coup je vais garder mes propriétés toutes moisies (en plus avec le snippet Visual Studio c’est limite plus rapide à écrire qu’un champ public =P).
>Je ne comprends pas le sens de ce "c’est vite vu" ^^'
En désassemblant les assemblies, on ne pourra pas distinguer l'utilisation de champs ou de propriété, vu que le résultat dans l'IL est le même.
>Pas de champ public.
Cette classe a été conçu pour faire autre chose que du DTO (POCO), c'est donc normal que l'API soit en corrélation avec cette conception (addition, conversion, transtypage, etc...).
Je n'aurais pas fait de champ public dans ce cas, car ce n'est pas un simple "stockeur" de données.
Je ne connais pas de classe du Framework qui ne sert que de "stockeur" de données (DTO), mais si t'en connais je suis preneur.
Ce que je cherche à faire comprendre, c'est que faire des propriétés publiques "par défaut" est une connerie. Exactement comme faire des champs publics "par défaut" l'est aussi. Et si on n'est dans un DTO (donc pas de méthodes, pas de services, etc...), des champs publiques montrent que vous n'avez absolument pas à chercher à étendre cette classe ou vous en servir pour autre chose que du transfert de données.
Tout ce qui est public doit être conçu pour être étendu, et mettre des "get/private set" aveuglement, c'est une connerie.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
>Bah surtout qu'à priori le compilo inline les propriétés simples (sans code spécifique)
Ce qui justifie mon aversion à ce décorum totalement inutile.
Ça veut juste dire qu'on ne perd pas de perfs à utiliser une propriété. Ça ne change en rien leur utilité.
bacelar a écrit:
> il y a fort à parier que -au moins par convention- on va rendre ce type immuable
Why ???
Si je veux un DTO avec 2 int, pourquoi chercher à sur-concevoir le truc ?
"si on ne le fait pas on se retrouve avec le risque de modifier de malheureuses copies d’objets éphémères"
Selon les bonnes pratiques, une structure doit
Être immuable
Représenter une valeur
Faire un maximum de 128 bits
Ne pas avoir souvent besoin d'être boxée
Dans tous les autres cas, on fait une classe. Il est rare qu'un DTO représente une valeur.
bacelar a écrit:
>aucun avantage au champ public, uniquement du danger potentiel
Parce que tu veux faire plus avec quelque chose qui n'a pas été CONÇU pour. Ce que je dis et redis, c'est qu'il faut concevoir les propriétés, comme le reste. Pour un DTO, la conception, c'est vite vue. => over-engineering.
Là encore, c'est une question de bonnes pratiques. Le truc c'est d'empêcher de faire quelque chose pour lequel ton code n'a pas été conçu.
bacelar a écrit:
>(Au passage, je te mets au défi d’ouvrir une classe du Framework .net, au pif, et d’y trouver des champs publics)
>Bah surtout qu'à priori le compilo inline les propriétés simples (sans code spécifique)
Je crois que c'est vite vue.
Sauf erreur de ma part, c'est le JIT qui inline. Donc les DLL du framework ne sont pas (encore) inlinées. Et à part les const ou les static readonly, je suis d'accord avec SuperCoincoin : le framework n'a pas de champ publique.
.
Utiliser des propriétés
Est aussi performant qu'utiliser un champ
Permet de rajouter des contrôles sur le getter ou le setter sans avoir à refactoriser le code
Permet d'avoir une visibilité différente sur le getter et le setter
Permet de sérialiser avec tous les sérialiseurs (alors qu'il n'y en a quasiment aucun qui utilise les champs) - utile pour un DTO
Permet le binding XAML
Permet d'implémenter une interface
Permet d'utiliser les initialiseurs d'objet
Permet de se baser sur autre chose qu'un champ
Permet l'override dans une classe enfant
Utiliser des champs plutôt que des propriétés
Permet d'économiser 10 caractères sans compter les espaces (9 si jamais tu préfixes tes champs par _).
Il y a 2 types de personnes : celles qui sont capables d'extrapoler à partir de données incomplètes.
>Permet de sérialiser avec tous les sérialiseurs (alors qu'il n'y en a quasiment aucun qui utilise les champs) - utile pour un DTO
What ???
De mon expérience, sérialisation WCF et XML "standard", c'est largement l'inverse, oui donc les champs publics sont très utile pour un DTO.
Je n'ai jamais, au grand jamais, dit que c'est plus rapide.
>"si on ne le fait pas on se retrouve avec le risque de modifier de malheureuses copies d’objets éphémères"
Bon, c'est un peu le but des DTO, non ??? d'avoir des objets éphémères et que ceux qui travaille avec (les couches réceptrices) font ce qu'ils veulent avec.
>Selon les bonnes pratiques, une structure doit
Le rapport entre structure de DTO ?
Moi, les structures, à part pour de l'empilage sur pile, j'ai dû mal à m'en servir.
>Le truc c'est d'empêcher de faire quelque chose pour lequel ton code n'a pas été conçu.
Pile-poil, exactement comme "get/private set" en totomatique. Il faut faire une conception avant d'écrire cela.
Ma conception pour les DTO, en général, c'est faire une copie des champs visibles pour la couche cible. Après, elle se démerde, c'est son DTO, et ce n'est qu'un DTO.
>le framework n'a pas de champ publique.
Peut-être qu'ils n'en avaient pas besoin.
>Permet d'économiser 10 caractères sans compter les espaces (9 si jamais tu préfixes tes champs par _).
La stratégie de l'homme de paille, pas très fair play comme argumentaire. On s'en cogne de ces conneries. L'avantage principale, c'est de tout de suite concevoir l'API de la classe et pas coller comme un robot "get/private set" juste parce que "ça encapsule", ce qui est faut.
Sommes-nous d'accord que "get/private set", ça encapsule que dalle ?
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Cette classe a été conçu pour faire autre chose que du DTO (POCO), c'est donc normal que l'API soit en corrélation avec cette conception (addition, conversion, transtypage, etc...).
Je n'aurais pas fait de champ public dans ce cas, car ce n'est pas un simple "stockeur" de données.
Tu m’as demandé, je cite "Pour une structure qui expose des coordonnées 2D ou 3D, vas-tu faire de propriété GetX, GetY, Get Z ???". La suite du débat portait sur la pertinence des propriétés face à de simples champs publics dans un tel contexte... à ce stade là il n’était aucunement question de DTO.
Ah, en fait c’est venu juste après ; tu m’as répondu, je cite "Bin non, passer par des propriétés X,Y,Z au lieu de champs, c'est déjà du travail inutile pour une simple classe "DTO"."
Je n’avais pas fait gaffe (trop concentré sur tes "why ???" en série), mais pour le coup c’est toi qui, d’une structure, est passé à un DTO d’une réponse à l’autre.
M’enfin. Ça ne change pas grand-chose au final (cf. plus bas), de mon point je ne vois aucun avantage à devoir changer mes habitudes sous prétexte qu’une classe est un simple conteneur "éphémère". Vraiment aucun.
bacelar a écrit:
>Permet de sérialiser avec tous les sérialiseurs (alors qu'il n'y en a quasiment aucun qui utilise les champs) - utile pour un DTO
What ???
Newtonsoft.Json, pour ne citer que celui-ci (et qui a le mérite d’être disponible en dll portable) ne sait, par défaut, jouer qu’avec des propriétés.
bacelar a écrit:
De mon expérience, sérialisation WCF et XML "standard", c'est largement l'inverse, oui donc les champs publics sont très utile pour un DTO.
Ça fait sans doute un bon siècle que je n’ai pas fait de dev WCF, mais de souvenir le proxy que génère VS (si on lui demande de générer les DTO justement), ne possède pas de champ public.
Autre exemple qui vaut ce qu’il vaut, l’outil de génération de classe de sérialisation de Visual Studio te génèrera des classes avec propriétés (et non des champs publics), que tu lui colles du JSON ou du XML.
Bref, pour ma part les DTO n’échappent pas à la "règle".
EDIT
bacelar a écrit:
Sommes-nous d'accord que "get/private set", ça encapsule que dalle ?
Celle-ci je veux bien te l’accorder (je ne suis pas non plus obtus comme garçon =P) ; dans la mesure ou un get/private set ne fait que cacher la donnée mais pas l’information, on ne peut pas réellement parler d’encapsulation.
Mais notre désaccord n’est pas lié à l’encapsulation (à fortiori maintenant qu’on a dérivé sur les DTO et autres classes de sérialisation). Et encore une fois, encapsulation ou non, un champ public n’a pas plus d’avantages qu’une bête propriété (qui respecte, elle, les guidelines du langage).
- Edité par SuperCoincoin 28 septembre 2016 à 10:52:14
Tu ne feras jamais de vérifications (sinon breaking change dans l'API)
Tu sérialiseras toujours avec un DataContractSerializer (si tu utilises Newtonsoft.JSON ou SharpSerializer, c'est galère d'utiliser des champs)
Tu ne comptes jamais générer automatiquement (tous les outils de génération automatique feront des propriétés)
Il ne devra jamais implémenter une interface (pas possible avec un champ)
Tu n'utiliseras pas d'outils comme StyleCop (qui te balancerait un warning comme quoi tu as un champ qui n'est pas privé)
Ok, utiliser des propriétés n'a pas d'avantage par rapport à un champ (mais pas d'inconvénient non plus).
Cependant, toutes ces contraintes (qui ne sont là que parce que tu ne veux pas utiliser des propriétés) signifie une maintenabilité inférieure. Perdre en maintenabilité parce que tu ne veux pas mettre { get; set; } à la fin de ta ligne, de mon côté, je ne cautionne pas.
Il y a 2 types de personnes : celles qui sont capables d'extrapoler à partir de données incomplètes.
Effectivement, j'ai donné le nom structure au lieu de DTO, car je pensais au structure au sens C.
> sous prétexte qu’une classe est un simple conteneur "éphémère". Vraiment aucun.
Juste que le fait que c'est une DTO ne sera pas évidant => convention de nommage, namespace pour compenser ?
Juste que les sérialisateurs vont t'emmerder à rendre les mutateurs publics, beurk !!!
Juste que tu ne prendras pas la peine d'analyser l'API offerte à l'utilisateur par l'ajout de cette propriété. Si par défaut, et avant toute analyses, les propriétés sont en private, je suis d'accord que ça change rien, sinon, non.
>Newtonsoft.Json
OK, convertir mon machin dans un truc utilisable par Newtonsoft.Json est trivial, mais dans l'autre sans, c'est conceptuellement bien plus dangereux. Qui peut le plus peut le moins.
Mes souvenirs de WCF sont aussi très lointain, mais cela m'avait gavé de mettre les setter en public pour toutes les propriétés public, avant de me rendre compte que ce que je voulais, c'était de simple DTO.
C'était peut-être un "bug" transitoire de WCF.
>Celle-ci je veux bien te l’accorder
C'est juste ça que je voulais !!! Merci.
>un champ public n’a pas plus d’avantages qu’une bête propriété
Pas d’inconvénients, et être sur que personne de raisonnable ne cherchera a en faire autre-chose qu'un DTO.
>(qui respecte, elle, les guidelines du langage)
Elles sont où pour les DTO ?
>Tu ne feras jamais de vérifications
Bin non, sinon, c'est pas un DTO. Les vérifications, c'est aux couches receptrices de les faire, selon leurs règles.
>Tu sérialiseras toujours avec un DataContractSerializer ...
Faire un wrapper pour d'autres Serializer, c'est pas la mort. Dans l'autre sens, je suis plus circonspect.
>tous les outils de génération automatique feront des propriétés
Des générateurs de DTO ???
>Il ne devra jamais implémenter une interface
Bin non, sinon, c'est pas un DTO....
>Tu n'utiliseras pas d'outils comme StyleCop
Quelle numéro de règles ? Elle ne prend pas en compte les spécificités DTO ?
>signifie une maintenabilité inférieure
Ce ne sont pas des problèmes, c'est même fait exprès, comme le "=delete" sur le constructeur de copie du C++ empêche de faire des trucs non prévu par le concepteur d'une classe. On gagne en maintenabilité car le mainteneur c'est que c'est un DTO, ou devrait savoir.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Bon, déjà, petit rappel : tu parles depuis un certain temps de DTO alors que l'exemple de base n'a rien d'un DTO.
bacelar a écrit:
>Newtonsoft.Json
OK, convertir mon machin dans un truc utilisable par Newtonsoft.Json est trivial, mais dans l'autre sans, c'est conceptuellement bien plus dangereux. Qui peut le plus peut le moins.
Tu dois toucher à ton DTO pour pouvoir le sérialiser/désérialiser en Json si tu utilises des champs. Tu n'as rien à faire si tu utilises des propriétés.
bacelar a écrit:
>Celle-ci je veux bien te l’accorder
C'est juste ça que je voulais !!! Merci.
Moi je ne l'accorde pas. Cela te fait une méthode get et une méthode set. Même si ces méthodes ne font rien de spécial, elles sont là, avec leurs modificateurs de visibilité et avec le champ libre pour faire tout ce que tu veux à l'intérieur.
bacelar a écrit:
>un champ public n’a pas plus d’avantages qu’une bête propriété
Pas d’inconvénients, et être sur que personne de raisonnable ne cherchera a en faire autre-chose qu'un DTO.
krimog a écrit:
Utiliser des propriétés
Est aussi performant qu'utiliser un champ
Permet de rajouter des contrôles sur le getter ou le setter sans avoir à refactoriser le code
Permet d'avoir une visibilité différente sur le getter et le setter
Permet de sérialiser avec tous les sérialiseurs (alors qu'il n'y en a quasiment aucun qui utilise les champs) - utile pour un DTO
Permet le binding XAML
Permet d'implémenter une interface
Permet d'utiliser les initialiseurs d'objet
Permet de se baser sur autre chose qu'un champ
Permet l'override dans une classe enfant
A part tout ça (+ ce que j'aurais oublié), un champ n'a pas d'inconvénients. Quant au fait que "personne de raisonnable ne cherchera a en faire autre-chose qu'un DTO", je dirais plutôt que personne de raisonnable ne laissera des champs publics.
bacelar a écrit:
>(qui respecte, elle, les guidelines du langage)
Elles sont où pour les DTO ?
Il n'y en a pas spécifiquement pour les DTO. Donc tu suis les guildelines plus globales qui disent qu'un champ doit être privé.
bacelar a écrit:
>Tu sérialiseras toujours avec un DataContractSerializer ...
Faire un wrapper pour d'autres Serializer, c'est pas la mort. Dans l'autre sens, je suis plus circonspect.
Tu es en train de parler de créer un wrapper pour sérialiser un DTO... C'est comme dire qu'il faut avoir un camion pour déplacer ta voiture...
bacelar a écrit:
>tous les outils de génération automatique feront des propriétés
Des générateurs de DTO ???
WCF n'a pas de problème pour t'en générer à partir d'un WSDL. Tu peux aussi en créer pour des API Rest qui utilisent Swagger (par exemple).
bacelar a écrit:
>Il ne devra jamais implémenter une interface
Bin non, sinon, c'est pas un DTO....
On parle d'une interface, pas d'une classe abstraite. Ce n'est nullement incompatible avec la notion de DTO, puisqu'une interface ne rajoute pas de logique. Ça ne fait que rajouter des contraintes. Si tu veux que tous tes DTO aient une propriété Id, ça n'a rien de choquant.
bacelar a écrit:
>Tu n'utiliseras pas d'outils comme StyleCop
Quelle numéro de règles ? Elle ne prend pas en compte les spécificités DTO ?
SA1401. Et il n'y a justement pas de spécificité pour un DTO. Ce n'est qu'un design pattern.
bacelar a écrit:
>signifie une maintenabilité inférieure
Ce ne sont pas des problèmes, c'est même fait exprès, comme le "=delete" sur le constructeur de copie du C++ empêche de faire des trucs non prévu par le concepteur d'une classe. On gagne en maintenabilité car le mainteneur c'est que c'est un DTO, ou devrait savoir.
Ou alors il se dit que c'est du code bâclé et le refait. Tu veux qu'on voit que c'est un DTO ? Entre le projet dans lequel il se trouve, son namespace, son nom et son éventuelle documentation, tu as bien assez d'endroits où l'indiquer. Pas besoin de violer une règle aussi basique que de ne pas faire de champs publics et dire "hey, regarde, mon code est crade, donc tu sais que c'est un DTO".
Il y a 2 types de personnes : celles qui sont capables d'extrapoler à partir de données incomplètes.
Pas d'encapsulation dans le tutoriel?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Mes applis Android
Mes applis Android
Mes applis Android
Mes applis Android
Mes applis Android
Mes applis Android