web-dev-qa-db-fra.com

Getters et setters à implémentation automatique vs champs publics

Je vois beaucoup d'exemples de code pour les classes C # qui font cela:

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

Ou, dans un code plus ancien, le même avec une valeur de support privé 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 simplement rendre ces membres publics, comme ci-dessous?

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

Pour être clair, je comprends la valeur des getters et setters lorsque vous avez besoin de faire une traduction des données sous-jacentes. Mais dans les cas où vous ne faites que transmettre les valeurs, cela semble inutilement verbeux.

71
tclem

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 donc nos normes de codage insistent toujours sur les 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 rupture de changement dans votre code; tout ce qui le consomme doit être recompilé pour fonctionner avec la nouvelle interface de classe, donc si quelque chose en dehors de votre contrôle consomme votre classe, vous pourriez avoir des problèmes.

47
Dexter

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

public int x { get; private set; }
31
Brad Wilson

Il encapsule la définition et l'accès de ces membres. Si un certain temps à partir de maintenant, un développeur pour le code doit changer de logique lorsqu'un membre est accédé ou défini, cela peut être fait sans changer le contrat de la classe.

9
Joseph Daigle

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 différemment les propriétés et les variables. Par exemple, vous ne pouvez pas passer des propriétés en tant que paramètres 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 maintenant vous devez utiliser des propriétés, votre interface devra changer et maintenant le code qui accède à la propriété x peut ne plus compiler comme il le faisait quand il était variable 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 compile.");
}

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

8
Rob Pilkington

Étant donné que les getters implémentés automatiquement prennent le même nom pour la propriété et les variables de stockage privé réelles. Comment pouvez-vous le changer à l'avenir? Je pense que le point étant dit, utilisez l'auto implémenté au lieu du champ afin que vous puissiez le changer à l'avenir si vous avez besoin d'ajouter de la logique à getter et setter.

Par exemple:

public string x { get; set; }

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

Comment changez-vous le setter auto getter ... par exemple pour setter vous autorisez seulement le réglage d'un format de numéro de téléphone valide ... comment changez-vous le code pour que seule la classe soit changée?

Mon idée est d'ajouter une nouvelle variable privée et d'ajouter les mêmes x getter et setter.

private string _x;

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

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

3
Nap

Setter and Getter vous permet d'ajouter une couche d'abstraction supplémentaire et en pur OOP vous devriez toujours accéder aux objets 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 string _SomeProperty  ;
public string SomeProperty 
{
  if ( _SomeProperty == null ) 
   return (string)Session [ "SomeProperty" ] ;
 else 
   return _SomeProperty ; 
}
}
3
Yordan Georgiev

Il faut également tenir compte de l'effet du changement sur les membres du public en ce qui concerne la liaison et la sérialisation. Les deux s'appuient souvent sur des propriétés publiques pour récupérer et définir des valeurs.

2
TheZenker

En outre, vous pouvez mettre des points d'arrêt sur les getters et les setters, mais vous ne pouvez pas sur les champs.

2
NotDan

Il convient également de noter que vous ne pouvez pas rendre les propriétés automatiques en lecture seule et que vous ne pouvez pas les initialiser en ligne. Ces deux choses sont des choses que j'aimerais voir dans une future version de .NET, mais je crois que vous ne pouvez faire ni l'un ni l'autre dans .NET 4.0.

La seule fois où j'utilise un champ de sauvegarde avec des propriétés ces jours-ci, 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.

Dans ces situations également, je définis les champs de sauvegarde directement lorsque des valeurs sont transmises à partir d'un constructeur (pas besoin d'essayer de déclencher OnPropertyChangedEvent (qui serait de toute façon NULL à ce moment-là), partout ailleurs j'utilise la propriété elle-même.

1
MrLane

AFAIK l'interface CIL générée est différente. Si vous changez un membre public en une propriété, vous changez son interface publique et devez reconstruire chaque fichier qui utilise cette classe. Cela n'est pas nécessaire si vous modifiez uniquement l'implémentation des getters et setters.

1
Ben Strasser

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

Sincères amitiés

1
marcospereira

Vous ne savez jamais si vous pourriez ne pas avoir besoin de traduire les données plus tard. Vous êtes prêt pour cela si vous cachez vos membres. Les utilisateurs de votre classe ne remarqueront pas si vous ajoutez la traduction car l'interface reste la même.

0
EricSchaefer

La plus grande différence est que, si jamais vous changez votre structure interne, vous pouvez toujours maintenir les getters et setters tels quels, en changeant leur logique interne sans blesser les utilisateurs de votre API.

0
gizmo

Si vous devez changer la façon dont vous obtenez x et y dans ce cas, vous pouvez simplement ajouter les propriétés plus tard. C'est ce que je trouve le plus déroutant. Si vous utilisez des variables de membre public, vous pouvez facilement le modifier ultérieurement en une propriété et utiliser des variables privées appelées _x et _y si vous devez stocker la valeur en interne.

0
Kibbee