25 votes

Le "set" privé en C# - j'ai du mal à m'y retrouver

J'ai vu beaucoup d'exemples de code écrits en utilisant quelque chose comme (veuillez pardonner le fait que ce soit horriblement théorique) :

public class Test
{
   public object Thingy { get; private set; }
}

Malheureusement, ce genre d'exemples n'explique jamais vraiment pourquoi 'set' est défini comme privé. Je me demande donc s'il n'y a pas un bon exemple courant qui me permettrait de comprendre pourquoi on utilise quelque chose comme ça.

Je le vois en quelque sorte - la propriété peut être exécutée pour traiter une logique supplémentaire en plus de la définition de ce champ. Je ne sais pas comment l'invoquer et pourquoi utiliser cette approche plutôt qu'une méthode setter générique.

27voto

spinon Points 6362

Ce serait le cas si vous avez une propriété que vous ne voulez pas que quelqu'un d'autre que votre classe puisse définir. Cela peut être pratique avec les identifiants de base de données. La classe interne peut le définir mais vous ne voulez pas que quelqu'un d'autre le modifie. Vous pouvez donc leur donner un accès en lecture mais pas en écriture.

EDIT : Un autre point sur ce sujet est que l'utilisation de ce que vous avez montré ici est utile pour les propriétés automatiques. Malheureusement, avec les propriétés automatiques, il n'est pas possible de spécifier seulement get, donc pour éviter d'exposer publiquement un setter, il est simplement rendu privé.

EDIT : J'ai pensé que je pourrais donner un exemple. Les propriétés automatiques sont excellentes pour un code propre et concis. Mais comme vous l'avez montré, il y a une limitation dans le fait que vous devez avoir get et set. Donc avant, c'était comme ça pour une propriété comme celle que vous avez montrée :

public class Test
{
   private object thingy;
   public object Thingy
   {
      get { return thingy; }
   }
}

Maintenant, nous pouvons nous débarrasser de cette déclaration privée inutile, mais il faut les deux. Il faut donc faire private pour contourner ce problème.

Je sais que c'est un peu exagéré comme explication, mais différentes choses m'ont traversé l'esprit.

9voto

Marc Gravell Points 482669

Pour prendre un exemple simple, il s'agit d'un moyen bon marché de créer un objet "suffisamment immuable" (pour l'utiliser dans le threading, l'état, etc.). Mais aussi partout où le client doit simplement ne devrait pas besoin de l'attribuer, ou on ne peut pas lui faire confiance pour l'attribuer (correctement).

Un autre exemple pourrait être une liste :

public List<Foo> Items {get;private set;}

puisque nous pourrions appeler obj.Items.Add() etc., mais nous rarement attribuer obj.Items = ... . Cependant, cet exemple est entaché par la nécessité d'une initialisation explicite dans le constructeur, et XmlSerializer déteste - pour être honnête pour les listes que j'utilise principalement :

private readonly List<Foo> items = new List<Foo>();
public List<Foo> Items {get { return items;}}

qui résout ces deux problèmes.

Autre exemple, le contraste :

private readonly int foo;
public int Foo {get{return foo;}}

vs

private readonly int foo;
public int Foo {get{return foo;} private set {foo=value;}}

ce modèle peut être utile dans la sérialisation, par exemple avec DataContractSerializer (avec l'ajout de certains attributs), car de nombreux sérialiseurs rechercheront toujours des accesseurs privés. Cela nous évite d'avoir à décorer nos interne l'état ( foo ), mais donne le placage de la vie privée au set .

En fin de compte, tout ce qui est peuvent être contournés et assignés via la réflexion, ainsi les privés set n'a pour but que d'éviter accidentel des dommages aux données.

4voto

Yuriy Faktorovich Points 33347

Le caractère privé en fait une propriété en lecture seule. Un exemple courant est le cas où plusieurs classes se partagent un même objet et où vous ne voulez pas qu'une autre classe puisse modifier l'instance.

3voto

Henk Holterman Points 153608

En fait, il s'agit d'une propriété en lecture seule. Si elle était écrite dans son intégralité (et non comme une propriété automatique), il suffirait de laisser de côté le setter.

Deux exemples qui sont en grande partie les mêmes :

class Foo1
{
   public int Id { get; private set; }
   public Foo1()
   {
       Id = lastId ++;
   }
}

class Foo2
{
   private int _id;   
   public int Id { get { return _id; } }
   public Foo2()
   {
       _id = lastId ++;
   }
}

2voto

Jimmy Hoffa Points 3651

J'ai vu cela utilisé avec le design :

public class whatever
{
    public string WhateverId { get; private set; }

    public static whatever Create(string whateverId)
    {
        return new whatever() { WhateverId = whateverId };
    }
}

Vous créez donc n'importe quelle classe, mais une fois qu'elle est créée, l'identifiant ne peut pas être modifié car cela pourrait casser les choses qui y sont connectées.

l'ensemble privé donne juste la syntaxe simple de l'initialisation, je l'aime bien pour certains scénarios.

Peut également être utilisé s'il est modifiable, mais vous devez le gérer lorsque des changements sont effectués.

public void SetWhateverId(string whateverId)
{
    DisconnectAllCurrentWhateverIdReferences();
    WhateverId = whateverId;
    ReconnectAllPreviousWhateverIdReferences();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X