Champs publics et propriétés automatiques

353

On nous dit souvent que nous devons protéger l'encapsulation en créant des méthodes getter et setter (propriétés en C #) pour les champs de classe, au lieu d'exposer les champs au monde extérieur.

Mais il y a de nombreuses fois où un champ est juste là pour contenir une valeur et ne nécessite aucun calcul pour obtenir ou définir. Pour ceux-ci, nous ferions tous ce numéro:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Eh bien, j'ai une confession, je ne pouvais pas supporter d'écrire tout cela (vraiment, il ne fallait pas l'écrire, il fallait le regarder), alors je suis devenu voyou et j'ai utilisé les champs publics.

Ensuite vient C # 3.0 et je vois qu'ils ont ajouté des propriétés automatiques:

public class Book
{
    public string Title {get; set;} 
}

ce qui est plus ordonné, et j'en suis reconnaissant, mais vraiment, qu'est-ce qui est si différent que de simplement rendre un domaine public?

public class Book
{
    public string Title;
}
IJ Kennedy
la source
6
J'ai converti un feild en une propriété juste pour pouvoir définir un point d'arrêt sur le passeur
Ian Ringrose
1
J'ai tendance à faire de tout ce qui n'est pas privé une propriété, car réaliser que je dois transformer un champ en propriété a conduit à des maux de tête inutiles. Propriétés, champs et méthodes. Oh mon! appelle une incompatibilité qui m'a mordu dans le passé.
Steven Wexler
2
L' propextrait de code permet de créer rapidement des propriétés. Tapez simplement proppuis tab.
Tono Nam

Réponses:

175

Dans une question connexe que j'avais il y a quelque temps, il y avait un lien vers une publication sur le blog de Jeff, expliquant certaines différences.

Propriétés et variables publiques

  • La réflexion fonctionne différemment entre les variables et les propriétés, donc si vous comptez sur la réflexion, il est plus facile d'utiliser toutes les propriétés.
  • Vous ne pouvez pas lier de données à une variable.
  • Changer une variable en une propriété est un changement de rupture. Par exemple:

    TryGetTitle(out book.Title); // requires a variable
Michael Stum
la source
24
"Changer une variable en une propriété est un changement de rupture." Bien sûr, cela ne s'applique que lors de l'écriture d'une bibliothèque réutilisable, ce que la plupart des développeurs ne font pas .
Steven
30
De plus, les propriétés, même les propriétés automatiques, peuvent être virtuelles, contrairement aux champs. Ainsi, une classe de base peut avoir une implémentation de champ de sauvegarde simple telle que produite par le compilateur pour une auto-prop, tandis que les classes dérivées peuvent effectuer une validation supplémentaire ou d'autres logique / calculs.
KeithS
28
Un champ est également une variable et peut être transmis par référence ( refou outmot clé), tandis qu'une propriété est une paire d'accesseurs et ne peut pas être transmise par référence. Par exemple, bool success = TryGetMyTitle(out myBook.Title);quelles utilisations outfonctionneront avec un champ et ne fonctionneront pas avec une propriété. Ceci est un exemple clair de la raison pour laquelle le changement de champ en propriété est un changement de rupture!
Jeppe Stig Nielsen
2
@KyleBaran Non, cela n'a pas beaucoup de sens car une propriété est une paire de méthodes d'accesseur, pas une variable. Une chose habituelle à faire est de déclarer une variable locale (éventuellement lire la propriété et mettre sa valeur dans la variable locale), passer la variable locale en tant que ref/ out, puis définir la propriété à la valeur que la variable locale a alors. Mais alors la méthode appelée n'accède pas elle-même à la propriété, elle accède à la variable locale que vous y avez créée.
Jeppe Stig Nielsen
5
@theberserker True, bien qu'en C # 6, vous pouvez faire public int Foo { get; }ce qui créera une propriété automatique avec un champ de support en lecture seule.
Michael Stum
83

Ignorant les problèmes d'API, la chose que je trouve la plus précieuse à propos de l'utilisation d'une propriété est le débogage.

Le débogueur CLR ne prend pas en charge les points d'arrêt de données (la plupart des débogueurs natifs le font). Par conséquent, il n'est pas possible de définir un point d'arrêt sur la lecture ou l'écriture d'un champ particulier sur une classe. Ceci est très limitant dans certains scénarios de débogage.

Les propriétés étant implémentées comme des méthodes très fines, il est possible de définir des points d'arrêt lors de la lecture et de l'écriture de leurs valeurs. Cela leur donne une grande longueur d'avance sur les champs.

JaredPar
la source
2
Dix ans plus tard, les points d'arrêt de données sont là, au moins pour .NET Core :)
Luaan
72

Le passage d'un champ à une propriété rompt le contrat (par exemple, tous les codes de référence doivent être recompilés). Ainsi, lorsque vous avez un point d'interaction avec d'autres classes - n'importe quel membre public (et généralement protégé), vous voulez planifier votre croissance future. Pour ce faire, utilisez toujours les propriétés.

Ce n'est rien pour en faire une propriété automatique aujourd'hui, et 3 mois plus tard, vous réaliserez que vous voulez le rendre chargé paresseux et mettre une vérification nulle dans le getter. Si vous aviez utilisé un champ, c'est un changement de recompilation au mieux et impossible au pire, selon qui et quoi d'autre dépend de vos assemblys.

Rex M
la source
9
J'ai aimé cette réponse car elle n'utilise pas les mots «réflexion», «interface» ou «dérogation». (dommage pour le 'contrat')
65

Tout simplement parce que personne ne l'a mentionné: vous ne pouvez pas définir de champs sur les interfaces. Donc, si vous devez implémenter une interface spécifique qui définit les propriétés, les propriétés automatiques sont parfois une fonctionnalité vraiment intéressante.

MartinStettner
la source
1
Je dirais que si vous avez besoin d'une interface qui définit des propriétés, ce devrait être une classe abstraite. Ce n'est pas parce que c # vous permet de définir des propriétés dans les interfaces que vous devez les utiliser. C'est une mauvaise conception.
Odys
8
@odyodyodys - Je ne suis pas sûr d'être d'accord sur le fait que c'est une mauvaise conception. Veuillez expliquer votre justification?
Zaid Masud
4
@odyodyodys Je suis d'accord avec zooone9243: Imp, du point de vue de la conception, il n'y a pas de différence entre déclarer une propriété et déclarer une paire getter / setter (ce qui est une pratique courante pour les interfaces).
MartinStettner
22
@ zooone9243, + MartinStettner: C'était il y a 6 mois, j'ai beaucoup appris depuis. Je le reprends :)
Odys
47

Une énorme différence qui est souvent négligée et qui n'est mentionnée dans aucune autre réponse: la priorité . Vous pouvez déclarer des propriétés virtuelles et les remplacer alors que vous ne pouvez pas faire de même pour les champs de membre public.

Zaid Masud
la source
10

Tout dépend de la gestion des versions et de la stabilité de l'API. Il n'y a pas de différence, dans la version 1 - mais plus tard, si vous décidez que vous devez en faire une propriété avec un certain type de vérification d'erreur dans la version 2, vous n'avez pas à changer votre API - aucun changement de code, n'importe où, autre que la définition du bien.

Reed Copsey
la source
10

Un autre avantage des propriétés implémentées automatiquement par rapport aux champs publics est que vous pouvez rendre les accesseurs définis privés ou protégés, en fournissant à la classe d'objets où elle a été définie un meilleur contrôle que celle des champs publics.

Arnaldo
la source
8

Il n'y a rien de mal à créer un champ public. Mais n'oubliez pas que la création getter/setteravec des privatechamps n'est pas une encapsulation. OMI, si vous ne vous souciez pas des autres fonctionnalités d'un Property, vous pourriez aussi bien le faire public.

fastcodejava
la source
1

Si vous décidez ultérieurement de vérifier que le titre est unique, en le comparant à une collection ou à une base de données, vous pouvez le faire dans la propriété sans modifier le code qui en dépend.

Si vous n'utilisez qu'un attribut public, vous aurez moins de flexibilité.

La flexibilité supplémentaire sans rompre le contrat est ce qui est le plus important pour moi à propos de l'utilisation des propriétés et, jusqu'à ce que j'aie réellement besoin de la flexibilité, la génération automatique est la plus logique.

James Black
la source
0

Une chose que je trouve très utile ainsi que toutes les raisons de code et de test est que s'il s'agit d'une propriété par rapport à un champ, c'est que l'IDE de Visual Studio vous montre les références d'une propriété mais pas d'un champ.

TrtlBoy
la source
0

Mon pov a fait quelques recherches

  1. Validation.
  2. Permet de remplacer l'accesseur pour modifier le comportement d'une propriété.
  3. Objectif de débogage. Nous pourrons savoir quand et ce que la propriété changera en définissant un point d'arrêt dans l'accesseur.
  4. Nous pouvons avoir un champ uniquement. Par exemple, public set () et private get (). Ce n'est pas possible avec le domaine public.

Cela nous donne vraiment plus de possibilités et d'extensibilité.

KunYu Tsai
la source