Devriez-vous créer des propriétés privées?


19
private string mWhatever;

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = value;
    }
}

J'ai vu des gens qui font des propriétés pour chaque membre, privé ou non ... est-ce que cela a un sens? Je pouvais voir que cela avait du sens dans 1% des cas lorsque vous souhaitez contrôler l'accès au membre à l'intérieur de la classe qui le contient, car si vous n'utilisiez pas de propriétés pour chaque membre, cela conduirait à des incohérences et vérifierait si le membre a un accès ou non (puisque vous avez accès aux deux dans le cadre de la classe).

Réponses:


17

Réponse courte: Oui , en cas de besoin. Sinon, utilisez un getter et un setter de propriété implémentés automatiquement commeprivate string Whatever { get; set;}

  • C'est très pratique lorsque vous utilisez une approche de domaine proche
  • Il est également pratique lorsqu'une logique spécifique doit être vérifiée lorsque vous définissez la valeur

Voici une description complète du moment où vous utiliserez des setters privés: utilisation de la propriété C # .


Il est également très facile de rendre la propriété publique plus tard si nécessaire.
Tom Pickles

4
Qu'est-ce qu'une approche de domaine proche ?
Trisped

1
Je parlais d'un setter privé dans une propriété de la classe. Il doit empêcher l'accès direct à la valeur définie à partir de l'objet et faciliter une vérification logique avant de définir la valeur.
Yusubov

avoir des variables privées avec des setter / getters publics (même s'ils sont juste naïfs) a également l'avantage que si votre code est compilé dans une bibliothèque, la signature restera inchangée si vous remplacez vos setter / getters naïfs par ceux qui ont un côté- etc., mais si vous utilisez une simple variable publique à la place, la signature de la bibliothèque changerait si vous la changiez en un w / setter / getters non naïf privé. .. ce qui signifierait que si votre bibliothèque changeait de cette manière, les consommateurs de votre bibliothèque devraient alors recompiler.
orion elenzil

12

Quelques bonnes réponses ici déjà, mais je pense que la plupart d'entre elles manquent un point de votre question:

J'ai vu des gens qui font des propriétés pour chaque membre, privé ou non ... est-ce que cela a un sens?

Je pense que cela est rarement nécessaire au préalable, pour chaque membre . Commencer avec

 private string Whatever;

Lorsque vous arrivez plus tard à un point où vous avez besoin encapsulation ou d'un point d'arrêt conditionnel pour ce membre spécifique, vous pouvez toujours le remplacer par une propriété du même nom - dans la plupart des cas sans changer le code qui l'utilise Whatever. Mais attention, il y a des différences subtiles, voir la réponse de Brian Rasmussen dans cet article SO (lien également donné par Emmad Kareem, +1).


+1, aussi, vous avez raison, la plupart des réponses ont manqué les points de question d'origine, nous sommes des types informatiques typiques :)
NoChance

Refactoriser un champ en une propriété après coup est un cauchemar; vous obligeant à recompiler tous les consommateurs. Changer une propriété automatique pour contenir une logique personnalisée est un jeu d'enfant. S'il y a même une légère chance que le code voit le refactor, ce sera beaucoup moins de travail si vous utilisez simplement les propriétés dès le début.
Dan

@Dan: dans la plupart des projets, j'ai vu que l'effort est tout à fait le même, vous devez recompiler dans les deux cas. Néanmoins, je pense que vous avez raison de dire que l'utilisation de propriétés, en particulier les propriétés automatiques, peut aider à éviter certains problèmes subtils de réflexion ou l'utilisation de variables membres dans les paramètres "out".
Doc Brown

@DocBrown En tout cas, ce n'est certainement pas une déclaration fourre-tout. Il y a de nombreuses raisons de rester simple et d'utiliser un champ. Si vous pouvez prédire un refactor cependant, même les problèmes subtils méritent d'être examinés.
Dan

7

L'un des plus grands avantages de cette approche est que vous maîtrisez moment où vos variables changent .

Considérer ce qui suit.
Vous déboguez un grand projet. Une certaine méthode lève une exception. Vous définissez un point d'arrêt et vous révélez qu'une certaine variable membre a une valeur incorrecte. Supposons que votre code repose très largement sur cette variable et que vous trouvez des centaines d'utilisations en écriture ( scénario Spaghetti ). Vous ne pouvez donc pas déterminer lequel de ces utilisations a attribué une mauvaise valeur.
Si le code est multithread, le débogage peut devenir un véritable cauchemar.

Avec la propriété, vous pouvez définir un point d'arrêt dans un setter . Combiné à une condition, il peut être cloué en une seule fois.

VC ++ a des points d'arrêt de données , mais il n'est disponible que pour le code non managé.


1

Si vous n'utilisez pas de propriété, votre seule autre option consiste à utiliser un champ pour stocker des données variables. Les propriétés et les champs présentent des différences importantes. La plupart de ces différences se trouvent dans les champs par rapport aux propriétés . Je vous propose d'étudier les différences puis de faire votre choix en fonction des besoins de votre application. Cependant, gardez à l'esprit que l'utilisation de champs au lieu de propriétés n'est pas la pratique OO courante en raison de leur nature et de leurs lacunes.


1

Les propriétés privées peuvent être très utiles pour encapsuler le comportement de choses internes à votre classe. Ce n'est pas parce qu'ils sont privés que vous ne devez pas profiter du sucre syntaxique que vous offrent les propriétés.


L'exemple donné est cependant médiocre. Les getters et setters de propriété de chaudière comme celui-ci sont presque toujours une mauvaise idée. Si vous utilisez C # 3.0 ou une version ultérieure, les propriétés automatiques sont une bien meilleure idée:

private string Whatever { get; set; };

C'est plus court, plus propre et beaucoup plus lisible. En fait, c'est à peine plus long que de simplement déclarer la variable de support.

Plus important encore, les propriétés automatiques peuvent être converties en propriétés complètes à tout moment sans changer la sémantique du reste du programme! Ainsi, si vous devez ajouter une validation ou une gestion des erreurs, vous pouvez le faire facilement.


En l'état, j'ai toujours pensé qu'il était dommage que vous ne puissiez pas avoir une propriété en lecture seule, pour appliquer uniquement la possibilité d'écrire sur la valeur dans le constructeur, (je préfère les types immuables ) mais cela a été ajouté en C # 6.0 comme "Auto-Property Initializers", qui vous permet de faire:

private string Whatever { get; } = ...;

ou

private string Whatever { get; };

de même que

    Whatever = ...;

chez le constructeur.


0

Il n'est pas absolument nécessaire de le faire pour les propriétés privées, mais cela permet de modifier la façon dont la propriété obtient / définit la valeur sous-jacente sans changer la façon dont elle est accessible.

Par exemple, en modifiant la façon dont la valeur sous-jacente est définie:

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = string.IsNullOrEmpty(value) ? string.Empty : value;
    }
}

0

Ouais

J'utilise personnellement cela comme mécanisme de mise en cache, et nous pourrions l'appeler la mise en cache au niveau de la propriété .

private List<User> users;
private List<User> Users
{
    get
    {
        if(users == null) users = new UserManager().GetUsers();
        return users;
    }
}

Maintenant, dans d'autres endroits de ma classe, j'utilise une Userspropriété au lieu d'un userschamp.

Une autre situation possible pourrait être lorsque vous souhaitez implémenter une logique sur un champ, mais de manière centralisée dans une classe. Ainsi, vous pouvez à la fois créer une GetFoo()méthode ou une Foopropriété pour le foochamp.

private string foo;
private string Foo
{
    get
    {
        return "Mr. " + foo;
    }
}

0

Autre chose à considérer:

Les propriétés réelles sont un détail d'implémentation. L'un des objectifs de la POO est d'essayer de minimiser l'exposition des détails de mise en œuvre lorsque cela est possible.

La raison en est que si vous masquez les propriétés et ne les exposez que par des getters et setters, vous avez bien plus de contrôle. Par exemple, votre getter peut valider son entrée et empêcher la propriété d'être définie sur un état non valide. Si la possibilité de modifier la valeur est critique dans le temps, le passeur peut également se protéger contre cela. Le getter, si obtenir la valeur réelle coûte cher pour une raison quelconque, peut effectuer une initialisation et / ou une mise en cache paresseuse.

Le fait d'avoir des getters et des setters exposés et des propriétés cachées signifie parfois que vous n'avez pas du tout besoin d'une propriété. Votre getter peut calculer la valeur lors de l'invocation, ou déléguer la tâche ailleurs, ou tout ce qui lui permet de répondre à ses spécifications. Ce qui est important dans votre classe, ce sont les informations auxquelles vous pouvez accéder, et non la façon dont ces informations sont représentées en interne.

Bien sûr, s'il n'y a pas de conséquences négatives à ce que quoi que ce soit en dehors de la classe puisse accéder directement à une propriété, vous devez simplement la rendre publique. Cependant, d'après mon expérience, de tels cas sont relativement rares.


0

Je sais que c'est une vieille question et tout ce que @Yusubov a dit est correct, mais en ce qui concerne son deuxième point sur la logique spécifique dans le setter, et puisque je n'ai vu personne mentionner spécifiquement cela, un exemple parfait serait quand votre classe implémente l' INotifyPropertyChangedinterface.

Ceci est utilisé une tonne dans WCF et Silverlight qui vous permet de savoir quand une propriété spécifique a changé via la logique de son setter comme dans la classe ci-dessous:

public class Settings : INotifyPropertyChanged
{
    public Settings() 
    { 
        this.CountryField = String.Empty; 
    }

    private string CountryField;
    public string Country
    {
        get { return this.CountryField; }
        set
        {
            if (Object.ReferenceEquals(this.CountryField, value)) { return; }

            this.CountryField = value;
            this.RaisePropertyChanged("Country");
        } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.