Getters et setters auto-implémentés vs. champs publics

Je vois beaucoup d’exemple de code pour les classes C # qui fait ceci:

public class Point { public int x { get; set; } public int y { get; set; } } 

Ou, dans l’ancien code, même avec une valeur de sauvegarde privée explicite et sans les nouvelles propriétés implémentées automatiquement:

 public class Point { private int _x; private int _y; public int x { get { return _x; } set { _x = value; } } public int y { get { return _y; } set { _y = value; } } } 

Ma question est pourquoi. Y a-t-il une différence fonctionnelle entre faire ce qui précède et rendre ces champs publics, comme ci-dessous?

 public class Point { public int x; public int y; } 

Pour être clair, je comprends la valeur des getters et des setters lorsque vous devez traduire certaines données sous-jacentes. Mais dans les cas où vous ne faites que passer les valeurs, cela semble inutilement verbeux.

J’ai tendance à être d’accord (que cela semble inutilement verbeux), bien que cela ait été un problème que notre équipe n’a pas encore résolu et que nos normes de codage insistent toujours sur des propriétés verbeuses pour toutes les classes.

Jeff Atwood en a parlé il y a quelques années. Le point le plus important qu’il a noté rétrospectivement est que le passage d’un champ à une propriété est un changement radical dans votre code; tout ce qui le consum doit être recompilé pour fonctionner avec la nouvelle interface de classe, donc si quelque chose en dehors de votre contrôle consum votre classe, vous pourriez avoir des problèmes.

Il est également beaucoup plus simple de le modifier plus tard:

 public int x { get; private set; } 

Il encapsule le paramétrage et l’access de ces membres. Si, à partir de maintenant, un développeur du code doit changer de logique lorsqu’un membre est accédé ou défini, cela peut se faire sans modifier le contrat de la classe.

L’idée est que même si la structure de données sous-jacente doit changer, l’interface publique de la classe ne devra pas être modifiée.

C # peut parfois traiter les propriétés et les variables différemment. Par exemple, vous ne pouvez pas transmettre de propriétés en tant que parameters ref ou out . Donc, si vous devez changer la structure des données pour une raison quelconque et que vous utilisiez des variables publiques et que vous devez maintenant utiliser des propriétés, votre interface devra changer et maintenant le code qui accède à la propriété x risque de ne plus comstackr comme X:

 Point pt = new Point(); if(Int32.TryParse(userInput, out pt.x)) { Console.WriteLine("x = {0}", pt.x); Console.WriteLine("x must be a public variable! Otherwise, this won't comstack."); } 

L’utilisation de propriétés dès le début évite cela, et vous pouvez vous sentir libre de modifier l’implémentation sous-jacente autant que nécessaire sans casser le code client.

Setter et Getter vous permettent d’append une couche d’abstraction supplémentaire. Dans la POO pure, vous devez toujours accéder aux objects via l’interface qu’ils fournissent au monde extérieur…

Considérez ce code, qui vous sauvera dans asp.net et qui ne serait pas possible sans le niveau d’abstraction fourni par les setters et les getters:

 class SomeControl { private ssortingng _SomeProperty ; public ssortingng SomeProperty { if ( _SomeProperty == null ) return (ssortingng)Session [ "SomeProperty" ] ; else return _SomeProperty ; } } 

Comme les getters implémentés automatiquement prennent le même nom pour la propriété et les variables de stockage privées réelles. Comment pouvez-vous le changer à l’avenir? Je pense que le fait est que l’utilisation de l’auto implémentée au lieu du champ afin que vous puissiez la modifier à l’avenir si vous avez besoin d’append de la logique à getter et setter.

Par exemple:

 public ssortingng x { get; set; } 

et par exemple vous utilisez déjà beaucoup de fois xa et vous ne voulez pas casser votre code.

Comment changez-vous le setter de getter automatique … Par exemple, pour setter, vous ne pouvez configurer qu’un format de numéro de téléphone valide … comment changez-vous le code pour que seule la classe soit modifiée?

Mon idée est d’append une nouvelle variable privée et d’append le même x getter et setter.

 private ssortingng _x; public ssortingng x { get {return x}; set { if (Datetime.TryParse(value)) { _x = value; } }; } 

Est-ce ce que vous voulez dire en le rendant flexible?

Il faut également prendre en compte l’effet du changement sur les membres publics en matière de liaison et de sérialisation. Ces deux éléments reposent souvent sur des propriétés publiques pour récupérer et définir des valeurs.

En outre, vous pouvez placer des points d’arrêt sur les getters et les setters, mais vous ne pouvez pas les utiliser dans les champs.

AFAIK l’interface CIL générée est différente. Si vous modifiez un membre public en une propriété, vous modifiez son interface publique et vous devez recréer chaque fichier utilisant cette classe. Ce n’est pas nécessaire si vous modifiez uniquement la mise en œuvre des getters et des setters.

Peut-être que simplement rendre les champs publics, vous pourriez vous conduire à un modèle de domaine plus anémique .

Sincères amitiés

Il est également intéressant de noter que vous ne pouvez pas créer de propriétés Auto Readonly et que vous ne pouvez pas les initialiser en ligne. Ce sont les deux choses que j’aimerais voir dans une future version de .NET, mais je pense que vous ne pouvez faire ni dans .NET 4.0.

La seule fois où j’utilise un champ de sauvegarde avec des propriétés, c’est lorsque ma classe implémente INotifyPropertyChanged et que je dois déclencher l’événement OnPropertyChanged lorsqu’une propriété est modifiée.

Aussi, dans ces situations, je définis les champs de sauvegarde directement lorsque des valeurs sont passées depuis un constructeur (inutile d’essayer et de déclencher le OnPropertyChangedEvent (qui serait NULL à ce stade de toute façon)), où que j’utilise la propriété elle-même.

Vous ne savez jamais si vous n’auriez peut-être pas besoin de traduire les données ultérieurement. Vous êtes prêt pour cela si vous cachez vos membres. Les utilisateurs de votre classe ne le remarqueront pas si vous ajoutez la traduction car l’interface rest la même.

La plus grande différence est que, si vous changez de structure interne, vous pouvez toujours conserver les règles et les parameters tels quels, en changeant leur logique interne sans nuire aux utilisateurs de votre API.

Si vous devez modifier la manière dont vous obtenez x et y dans ce cas, vous pouvez simplement append les propriétés ultérieurement. C’est ce que je trouve le plus déroutant. Si vous utilisez des variables de membre public, vous pouvez facilement modifier cette propriété ultérieurement et utiliser des variables privées appelées _x et _y si vous devez stocker la valeur en interne.

Les Setters et les Getters sont en principe mauvais (ils sont une mauvaise odeur d’OO – je vais arrêter de dire qu’ils sont anti-pattern car ils sont vraiment nécessaires parfois).

Non, techniquement, il n’y a pas de différence et lorsque je veux vraiment partager l’access à un object ces jours-ci, je le rend parfois public final au lieu d’append un getter.

La façon dont les créateurs et les attaquants étaient “vendus” est que vous pourriez avoir besoin de savoir que quelqu’un obtient une valeur ou en change une, ce qui n’a de sens qu’avec les primitives.

Les objects de sac de propriétés tels que les objects DAO, DTO et les objects d’affichage sont exclus de cette règle car ils ne sont pas des objects dans une véritable signification “OO Design” du mot Object. (Vous ne pensez pas à “Passer des messages” à un DAO, c’est simplement une stack de paires atsortingbut / valeur).