web-dev-qa-db-fra.com

Y a-t-il des raisons d'utiliser des propriétés privées en C #?

Je viens de me rendre compte que le C # propriété de construction peut également être utilisé avec un modificateur d'accès privé:

private string Password { get; set; }

Bien que ce soit techniquement intéressant, je ne peux pas imaginer quand l’utiliser, puisqu'un champ privé implique même moins de cérémonie:

private string _password;

et je ne peux pas imaginer quand j’aurai besoin de pouvoir en interne get mais pas set ou set mais pas get un champ privé:

private string Password { get; }

ou

private string Password { set; }

mais peut-être existe-t-il un cas d'utilisation avec classes imbriquées/héritées ou peut-être qu'un objet get/set pourrait contenir logique au lieu de simplement restituer la valeur de la propriété, bien que j'aie tendance à garder les propriétés strictement simples et laisser les méthodes explicites faire toute la logique, par exemple GetEncodedPassword().

Quelqu'un utilise-t-il des propriétés privées en C # pour quelque raison que ce soit ou s'agit-il simplement d'une de ces constructions techniquement possibles mais encore rarement utilisées en code réel?

Addenda

Jolies réponses, en les lisant, j'ai choisi ces utilisations pour les propriétés privées:

  • quand les champs privés doivent être chargés paresseusement
  • lorsque les champs privés nécessitent une logique supplémentaire ou sont des valeurs calculées
  • puisque les champs privés peuvent être difficiles à déboguer
  • afin de "se présenter un contrat"
  • convertir/simplifier en interne une propriété exposée dans le cadre de la sérialisation
  • envelopper des variables globales à utiliser dans votre classe
201
Edward Tanguay

Je les utilise si j'ai besoin de mettre en cache une valeur et de vouloir la charger paresseuse.

private string _password;
private string Password
{
    get
    {
        if (_password == null)
        {
            _password = CallExpensiveOperation();
        }

        return _password;
    }
}
179
Shaun Bowe

La principale utilisation de cela dans mon code est l'initialisation lente, comme d'autres l'ont mentionné.

Une autre raison pour les propriétés privées au-dessus des champs est que les propriétés privées sont beaucoup plus faciles à déboguer que les champs privés. Je veux souvent savoir des choses comme "ce champ est en train d'être défini de manière inattendue; qui est le premier appelant qui définit ce champ?" et c'est beaucoup plus facile si vous pouvez simplement mettre un point d'arrêt sur le setter et appuyer sur Go. Vous pouvez mettre la connexion là-bas. Vous pouvez y mettre des mesures de performance. Vous pouvez mettre en place des contrôles de cohérence exécutés dans la construction de débogage. 

En gros, cela revient à: le code est beaucoup plus puissant que data . Toute technique qui me permet d’écrire le code dont j'ai besoin est bonne. Les champs ne vous permettent pas d'écrire du code, mais les propriétés. 

117
Eric Lippert

peut-être y a-t-il un cas d'utilisation avec des classes imbriquées/héritées ou peut-être qu'un get/set pourrait contenir une logique au lieu de simplement restituer la valeur de la propriété

Personnellement, je l'utilise même quand je n'ai pas besoin de logique pour le getter ou le setter d'une propriété. L'utilisation d'une propriété, même privée, permet de pérenniser votre code afin que vous puissiez ajouter la logique à un getter ultérieurement, si nécessaire.

Si j'estime qu'une propriété peut éventuellement nécessiter une logique supplémentaire, je l'envelopperai parfois dans une propriété privée au lieu d'utiliser un champ, juste pour ne pas avoir à modifier mon code ultérieurement.


Dans un cas semi-lié (bien que différent de votre question), j'utilise très souvent les setters privés sur des propriétés publiques:

public string Password 
{
    get; 
    private set;
}

Cela vous donne un getter public, mais garde le setter privé.

37
Reed Copsey

L’initialisation paresseuse est un endroit où elles peuvent être ordonnées, par exemple.

private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */);

private MyType MyType { get { return this.mytype.Value; } }

// In C#6, you replace the last line with: private MyType MyType => myType.Value;

Ensuite, vous pouvez écrire: this.MyType partout plutôt que this.mytype.Value et encapsuler le fait qu’il est instancié paresseusement à un seul endroit.

Ce qui est dommage, c'est que C # ne prend pas en charge l'étendue du champ de sauvegarde à la propriété (c'est-à-dire en le déclarant dans la définition de la propriété) pour le masquer complètement et garantir qu'il ne peut être consulté que par l'intermédiaire de la propriété.

19
Greg Beech

Une bonne utilisation des propriétés privées uniquement sont les valeurs calculées. Plusieurs fois, j'ai eu des propriétés qui sont privées en lecture seule et qui font juste un calcul sur d'autres champs de mon type. Ce n'est pas digne d'une méthode et n'est pas intéressant pour d'autres classes, donc c'est une propriété privée.

17
JaredPar

Le seul usage auquel je puisse penser

private bool IsPasswordSet 
{ 
     get
     {
       return !String.IsNullOrEmpty(_password);
     }
}
12
Lukasz Madon

Les propriétés et les champs ne sont pas un à un. Une propriété concerne l'interface d'une classe (qu'il s'agisse de l'interface publique ou interne), tandis qu'un champ concerne l'implémentation de la classe. Les propriétés ne doivent pas être vues comme un moyen de simplement exposer des champs, elles doivent être vues comme un moyen de révéler l'intention et le but de la classe. 

Tout comme vous utilisez des propriétés pour présenter un contrat à vos consommateurs sur ce qui constitue votre classe, vous pouvez également vous présenter un contrat pour des raisons très similaires. Alors oui, j'utilise des propriétés privées quand cela a du sens. Parfois, une propriété privée peut masquer des détails d'implémentation tels que le chargement différé, le fait qu'une propriété est en réalité une agglomération de plusieurs champs et aspects, ou qu'une propriété doit être pratiquement instanciée à chaque appel (think DateTime.Now). Il y a certainement des moments où il est logique d'imposer cela même sur vous-même dans le backend de la classe.

8
Matt Greer

Je les utilise en sérialisation, avec des éléments tels que DataContractSerializer ou protobuf-net qui prennent en charge cet usage (XmlSerializer ne le fait pas). C'est utile si vous avez besoin de simplifier un objet dans le cadre de la sérialisation:

public SomeComplexType SomeProp { get;set;}
[DataMember(Order=1)]
private int SomePropProxy {
    get { return SomeProp.ToInt32(); }
    set { SomeProp = SomeComplexType.FromInt32(value); }
}
7
Marc Gravell

Une chose que je fais tout le temps est de stocker des variables/cache "globales" dans HttpContext.Current

private static string SomeValue{
  get{
    if(HttpContext.Current.Items["MyClass:SomeValue"]==null){
      HttpContext.Current.Items["MyClass:SomeValue"]="";
    }
    return HttpContext.Current.Items["MyClass:SomeValue"];
  }
  set{
    HttpContext.Current.Items["MyClass:SomeValue"]=value;
  }
}
6
Earlz

J'utilise des propriétés privées pour réduire le code d'accès aux sous-propriétés souvent utilisées.

    private double MonitorResolution
    {
        get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
    }

C'est utile s'il y a beaucoup de sous-propriétés.

5
Yohanes Nurcahyo

Je les utilise de temps en temps. Ils peuvent faciliter le débogage lorsque vous pouvez facilement insérer un point d'arrêt dans la propriété ou ajouter une instruction de journalisation, etc.

Cela peut également être utile si vous devez modifier ultérieurement le type de vos données ou si vous devez utiliser la réflexion.

5
Hans Olsson

Il est courant de ne modifier que les membres avec des méthodes get/set, même privées. Maintenant, la logique derrière tout ceci est que vous sachiez que votre get/set se comporte toujours d'une manière particulière (par exemple, déclencher des événements) qui ne semble pas avoir de sens puisque ceux-ci ne seront pas inclus dans le schéma de propriétés ... mais les vieilles habitudes ont la vie dure.

2
corsiKa

Cela est parfaitement logique lorsqu'il existe une logique associée à la propriété définie ou get (pensez à l'initialisation lente) et que la propriété est utilisée à quelques endroits de la classe.

Si c'est juste un terrain droit? Rien ne vient à l'esprit comme une bonne raison.

2
Marc

Je sais que cette question est très ancienne, mais les informations ci-dessous ne figuraient dans aucune des réponses actuelles.

Je ne peux pas imaginer quand j'aurais besoin de pouvoir obtenir en interne, mais pas réglé

Si vous injectez vos dépendances, vous voudrez peut-être un Getter sur une propriété et non un séparateur, car cela dénoterait une propriété en lecture seule. En d'autres termes, la propriété ne peut être définie que dans le constructeur et ne peut être modifiée par aucun autre code de la classe.

De plus, Visual Studio Professional fournira des informations sur une propriété et non sur un champ, ce qui facilitera la visualisation de l'utilisation de votre champ.

 PorpField 

0
Guy

Certaines utilisations plus exotiques de champs explicites incluent:

  • vous devez utiliser ref ou out avec la valeur - peut-être parce que c'est un compteur Interlocked
  • il est intentionnel pour représenter la présentation fondamentale, par exemple, sur une struct avec une présentation explicite (peut-être mapper sur un cliché C++ ou le code unsafe)
  • historiquement, le type a été utilisé avec BinaryFormatter avec la gestion automatique des champs (le passage à des accessoires automatiques modifie les noms et rompt ainsi le sérialiseur)
0
Marc Gravell

Comme personne ne l’a mentionné, vous pouvez l’utiliser pour valider des données ou verrouiller des variables.

  • Validation

    string _password;
    string Password
    {
        get { return _password; }
        set
        {
            // Validation logic.
            if (value.Length < 8)
            {
                throw new Exception("Password too short!");
            }
    
            _password = value;
        }
    }
    
  • Verrouillage

    object _lock = new object();
    object _lockedReference;
    object LockedReference
    { 
        get
        {
            lock (_lock)
            {
                return _lockedReference;
            }
        }
        set
        {
            lock (_lock)
            {
                _lockedReference = value;
            }
        }
    }
    

    Remarque: lorsque vous verrouillez une référence, vous ne verrouillez pas l'accès aux membres de l'objet référencé.

Référence paresseuse: lors du chargement paresseux, vous pouvez avoir besoin de le faire de manière asynchrone pour laquelle il existe maintenant AsyncLazy . Si vous utilisez une version antérieure à celle de Visual Studio SDK 2015 ou ne l'utilisez pas, vous pouvez également utiliser AsyncLazy d'AsyncEx.

0