Pourquoi ai-je besoin d’un champ privé exposé via une propriété publique?

Je viens principalement du monde Java. Ainsi, les propriétés C # ont l’air bien.

Je sais qu’avec C # 3.0 ou supérieur, je peux utiliser les propriétés automatiques. Je l’aime encore plus :).

Ma question concerne un code (peut-être plus ancien) où je peux voir ceci:

private int age; public int Age { get { return age; } set { age = value; } } 

Pourquoi ai-je besoin de l’ère des champs privés? Qu’est-ce que je cache vraiment ici?

MODIFIER:

Je comprends tout à fait la nécessité du getter et du setter. J’ai mentionné que je venais du monde Java et que je le fais tout le temps.

Je comprends que les propriétés automatiques de C # 3.0 ou supérieures soient un sucre syntatique. Mais peut-être que ma question a une réponse plus simple. Cela signifie-t-il que (ci-dessous C # 3.0) la propriété ne détient aucune valeur? Donc, il doit obtenir la valeur d’un autre domaine?

Les anciennes versions de C # n’avaient pas de propriétés automatiques, vous deviez donc déclarer vos variables sur lesquelles les propriétés agissaient comme dans votre exemple. Ces jours, le même code pourrait être exprimé comme:

 public int Age { get; set; } 

Je pense que cela répond à votre question. Cependant, si vous demandez “pourquoi ne pas simplement avoir public int Age; et laisser les programmeurs définir directement la valeur sur le champ?”, Alors:

La première chose à garder à l’esprit est que les accesseurs de propriétés sont compilés en méthodes. Cela signifie qu’elle a une ABI différente de la simple lecture / écriture dans une variable membre de la classe, même si, syntaxiquement, elle a la même apparence que si vous aviez:

 class Fu { public int Age; } 

Cela signifie donc que si, à un moment donné, vous devez append une notification indiquant que le champ Age a été modifié – si vous utilisez des propriétés, vous pouvez facilement append cette logique de notification au configurateur de propriétés sans interrompre ABI.

 public int Age { get { return age; } set { age = value; NotifySomeOtherCode (); } } 

Si vous commencez avec un champ public, sa modification ultérieure en propriété modifiera l’ABI, ce qui est mauvais pour tout programme pouvant dépendre de votre assembly. Il est donc préférable de commencer par les propriétés.

Si tout va bien j’ai du sens …

Les propriétés automatiques n’étaient pas sockets en charge dans les anciennes versions du compilateur C #.

Le code ci-dessus est plus ou moins équivalent à ceci (en supposant que le champ n’est jamais réellement utilisé directement):

 public int Age { get; set; } 

Dans ce cas, vous n’en avez pas besoin. Si vous avez besoin de faire autre chose dans le setter ou le getter, cependant, la propriété automatique ne fonctionnera pas – vous aurez besoin du champ privé à manipuler.

La réponse standard serait “d’encapsuler les détails de la mise en œuvre de comment et où l’âge est stocké”.

Pour les besoins de la récupération, un exemple plus réaliste pourrait être qu’un jour, vous pourriez potentiellement vouloir accéder à la valeur de manière à rendre l’access direct moins intéressant. Par exemple, s’il s’agit d’une valeur que vous pouvez mettre en cache ailleurs ou d’une valeur calculée.

En termes d’encapsulation du processus de paramétrage, cela signifie que vous pouvez intégrer une validation au niveau du modèle dans le setter; si quelqu’un essaie de définir une valeur conceptuellement invalide, vous pouvez lancer une IllegalArgumentException et la rejeter.

Dans ces cas, l’encapsulation signifie que tout votre code existant n’a pas à changer car vous devez envelopper la valeur dans quelque chose.

Les propriétés automatiques en C #, une fois compilées, ont un fonctionnement identique à celui du code ci-dessus. Le compilateur génère un champ de support pour vous.

Vous avez donc besoin de quelque chose qui sauvegarde une propriété – un champ ou un code – c’est simplement que c’est pris en charge pour vous avec le raccourci des propriétés automatiques.

Les propriétés ne sont qu’un bon moyen d’écrire une paire de méthodes get et set . En Java, vous feriez ceci:

 private int age; public int getAge() { return age; } public void setAge(int value) { age = value; } 

Vous avez besoin du champ privé pour stocker l’âge quelque part – getAge et setAge ne sont que des méthodes.

La même chose s’applique à C # pour les versions antérieures à 3.0:

 private int age; public int Age { get { return age; } set { age = value; } } 

Il s’agit d’une méthode get et d’une méthode set, juste bien appariées afin que vous puissiez écrire x.Age = 21 au lieu de x.setAge(21) .

Avec les propriétés automatiques, le compilateur C # génère le champ privé pour vous (mais il est toujours là!):

 public int Age { get; set; } 

L’avantage des propriétés automatiques est que vous ne devez plus créer vous-même le champ de sauvegarde manuellement.

L’avantage de la version manuelle est que vous pouvez append une logique supplémentaire aux méthodes get et set, par exemple la validation des parameters:

 private int age; public int Age { get { return age; } set { if (value < 0) throw new ArgumentException(); age = value; } } 

Peut-être voulez-vous changer le comportement du passeur ou du getter plus tard. par exemple, notez que la valeur a été modifiée de l’extérieur cela ne serait pas possible avec un champ public sans propriétés

  private int age; public int Age { get { return age; } set { age = value; Log("value of age changed"); } } 

Avec un age public sur le terrain, vous deviez le consigner partout dans le code où vous modifiez la valeur de l’âge.

Dans ce cas, vous ne cachez rien, mais cela vous donnera la liberté d’append ultérieurement une logique get / set à votre champ privé. Donc, toute personne qui utilise la propriété ne remarquera pas la différence dans le futur.

Dans le cas simple rien. Cependant, vous facilitez la maintenance de l’interface avec la classe si l’implémentation de l’une ou l’autre de ces méthodes nécessite du code supplémentaire.

Prenez par exemple si vous devez append un événement changeant au configurateur.

  public int Age { get { return age; } set { if ( age != value) { age = value; OnAgeChanged(); } } } 

Vous pouvez le faire avec une propriété et ne pas casser le code client. Un champ n’a pas cet avantage.

Avec les propriétés automatiques, vous n’avez pas besoin de faire cela. Il n’ya rien de mal à cela, mais avec les propriétés automatiques, vous aurez toujours votre signature de propriété , ce qui est l’important. Avant les propriétés automatiques, vous deviez avoir un champ de sauvegarde pour votre propriété. Tant que vous avez une propriété automatique, vous pouvez ultérieurement la changer au format avec un champ de sauvegarde explicite, et la signature rest la même.

Mais il n’y a rien de mal à cela. Sauf que la convention est de plus en plus utilisée pour appeler le champ de sauvegarde privé “_age”.

(Je suppose que vous savez pourquoi vous voulez avoir une propriété , qu’elle soit automatique ou non, au lieu d’un champ public. La raison en est que l’object a une signature différente si vous changez le champ de formulaire public en propriété publique, il est donc plus sûr de commencer avec une propriété, même s’il n’ya pas de logique supplémentaire.)

Les Getters et les Setters sont l’interface publique avec laquelle les autres classes interagissent. Dans les systèmes complexes, on finit généralement par valider et effectuer d’autres tâches à l’intérieur du getter et du setter.

Le domaine privé est à usage interne. Si vous devez modifier la valeur depuis l’intérieur de la classe mais ignorer tout le travail supplémentaire, vous modifierez la variable privée.