Question

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

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

Ou, dans l'ancien code, identique 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. Existe-t-il une différence fonctionnelle entre faire ce qui précède et simplement rendre ces champs publics aux membres, 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 faire une traduction des données sous-jacentes. Mais dans les cas où vous ne faites que transmettre les valeurs, cela semble inutile.

Était-ce utile?

La solution

J'ai tendance à être d'accord (que cela semble inutile), 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 traité 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 une briser le changement dans votre code; tout ce qui le consomme doit être recompilé pour fonctionner avec la nouvelle interface de classe. Par conséquent, si quelque chose en dehors de votre contrôle utilise votre classe, vous pourriez avoir des problèmes.

Autres conseils

Il est également beaucoup plus simple de le modifier ultérieurement:

public int x { get; private set; }

Il encapsule la configuration et l’accès de ces membres. Si à partir de maintenant, un développeur de 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.

L'idée est que même si la structure de données sous-jacente doit être modifiée, 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 paramètres de référence ou de sortie . Donc, si vous avez besoin de changer la structure de données pour une raison quelconque et que vous utilisez des variables publiques et que vous devez maintenant utiliser des propriétés, votre interface devra changer et le code qui accède à la propriété x ne sera peut-être plus compilé comme il le faisait lorsqu'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 vous en évite. Vous pouvez également modifier l'implémentation sous-jacente autant que vous le souhaitez sans casser le code client.

Setter and Getter vous permet d’ajouter une couche d’abstraction supplémentaire. En POO pur, vous devez toujours accéder aux objets via l’interface fournie 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 ; 
}
}

Depuis, 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 l’important, c’est que l’utilisation automatique implémentée au lieu de champ vous permette de le modifier à l’avenir si vous avez besoin d’ajouter une logique à getter et à setter.

Par exemple:

public string x { get; set; }

et par exemple, vous utilisez déjà x souvent et vous ne voulez pas casser votre code.

Comment modifiez-vous le paramètre de lecture automatique ... par exemple, vous ne permettez que la définition d'un format de numéro de téléphone valide ... comment modifiez-vous le code pour que seule la classe soit modifié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 par flexibilité?

Il convient également de prendre en compte l'effet de la modification apportée aux membres du public en matière de liaison et de sérialisation. Ces deux méthodes reposent souvent sur des propriétés publiques pour extraire et définir des valeurs.

De plus, vous pouvez définir des points d'arrêt sur les accesseurs et les setters, mais pas sur les champs.

Autant que je sache, 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 devez reconstruire chaque fichier utilisant cette classe. Ce n'est pas nécessaire si vous ne modifiez que l'implémentation des getters et des setters.

Simplement rendre les champs publics, vous pourriez vous diriger vers un modèle de domaine anémique plus .

Cordialement

Il est également intéressant de noter que vous ne pouvez pas créer des propriétés automatiques en lecture seule et que vous ne pouvez pas les initialiser en ligne. Ce sont 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 ces jours-ci, c'est quand ma classe implémente INotifyPropertyChanged et que je dois déclencher l'événement OnPropertyChanged lorsqu'une propriété est modifiée.

De plus, dans ces situations, je définis les champs de sauvegarde directement lorsque des valeurs sont transmises à partir d'un constructeur (inutile d'essayer de déclencher OnPropertyChangedEvent (ce qui serait de toute façon NULL à ce stade)), partout où 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éparé à cela si vous cachez vos membres. Les utilisateurs de votre classe ne remarqueront pas si vous ajoutez la traduction puisque l'interface reste la même.

La différence majeure est que, si vous modifiez jamais votre structure interne, vous pouvez toujours conserver les accesseurs et les configurateurs tels quels, en modifiant leur logique interne sans nuire aux utilisateurs de votre API.

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 en changer une propriété ultérieurement et utiliser des variables privées appelées _x et _y si vous devez stocker la valeur en interne.

Les petters et les getters sont mauvais en principe (ils dégagent une mauvaise odeur de OO - je n’arrêterai pas de dire qu’ils sont un anti-modèle parce qu’ils sont vraiment nécessaires parfois).

Non, il n'y a techniquement aucune différence et lorsque je souhaite réellement partager l'accès à un objet ces jours-ci, je le rends parfois public en final au lieu d'ajouter un getter.

La manière dont les setters et les getters ont été "vendus" est-il nécessaire de savoir que quelqu'un obtient une valeur ou en modifie une - ce qui n'a de sens que pour les primitives.

Les objets sac de propriétés tels que les objets DAO, les objets DTO et les objets d'affichage sont exclus de cette règle, car ils ne sont pas des objets d'une véritable "conception OO". signification du mot objet. (Vous ne pensez pas à "transmettre des messages" à un DAO, c'est simplement une pile de paires attribut / valeur).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top