Quelle est la différence entre un champ et une propriété?


1131

En C #, qu'est-ce qui différencie un champ d'une propriété et quand doit-il être utilisé à la place d'une propriété?


32
Microsoft répond directement à cette question (pour tous les langages .NET) dans le cadre de ses directives de conception des membres . Pour plus de détails, voir les articles Property Design et Field Design . Notez qu'il existe une distinction entre les membres d' instance et les membres statiques .
DavidRR

Réponses:


979

Les propriétés exposent les champs. Les champs doivent (presque toujours) rester privés à une classe et accessibles via les propriétés get et set. Les propriétés fournissent un niveau d'abstraction vous permettant de modifier les champs tout en n'affectant pas la manière externe à laquelle ils sont accédés par les choses qui utilisent votre classe.

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kent souligne que les propriétés ne sont pas nécessaires pour encapsuler les champs, elles peuvent faire un calcul sur d'autres champs ou servir à d'autres fins.

@GSS souligne que vous pouvez également faire une autre logique, telle que la validation, quand une propriété est accédée, une autre fonctionnalité utile.


185
Il convient de noter que les propriétés ne sont pas requises pour encapsuler les champs. Il ne pouvait y avoir aucun champ derrière la propriété. Cela peut être un calcul ou renvoyer une constante ou autre chose.
Kent Boogaart

9
"tout en n'affectant pas la manière externe dont ils sont accédés par les choses qui utilisent votre classe." pardonnez-moi si je ne comprends pas bien, alors, mais pourquoi le besoin de modificateurs d'accès devant les propriétés du tout, si le champ derrière semble gérer cela? c'est-à-dire pourquoi rendre une propriété autre chose que publique?
Chucky

18
Votre réponse était juste avant les modifications et les commentaires incorrects de vote étrange. Une propriété doit toujours encapsuler un ou plusieurs champs, et ne doit jamais effectuer de travaux lourds ou de validation. Si vous avez besoin d'une propriété telle qu'un nom d'utilisateur ou un mot de passe pour avoir la validation, changez leur type de chaînes en objets de valeur . Il existe un contrat tacite entre un créateur de classe et le consommateur. Les champs contiennent l'état, les propriétés exposent l'état à l'aide d'un ou plusieurs champs, les vides changent d'état (levage lourd) et les fonctions exécutent des requêtes (levage lourd) .Ce n'est pas une pierre, juste des attentes lâches.
Suamere

6
@jpaugh Si je suis un consommateur de classe, je respecte les contrats définis par le créateur de la classe. Si une propriété est string, mon contrat est le suivant: attribuez des caractères jusqu'à ~ 2bils de longueur. Si une propriété est DateTime, mon contrat est: attribuer des numéros dans les limites de DateTime, que je peux rechercher. Si le créateur ajoute des contraintes aux setters, ces contraintes ne sont pas communiquées. Mais si, au lieu de cela, le créateur change le type de stringen Surname, alors leur nouvelle classe Surname communique les contraintes et la propriété public Surname LastNamen'a pas de validation setter. Aussi, Surnameest réutilisable.
Suamere

4
Et puisque Surname, dans mon exemple, est réutilisable, vous n'avez pas à vous soucier plus tard de copier / coller ces validations dans un setter de propriétés à d'autres endroits dans le code. Vous ne vous demandez pas non plus si la validation d'un nom de famille se fait à plusieurs endroits si vous modifiez les règles commerciales des noms de famille. Consultez le lien que j'ai publié sur Value Objects
Suamere

261

Les principes de programmation orientée objet disent que le fonctionnement interne d'une classe doit être caché au monde extérieur. Si vous exposez un champ, vous exposez essentiellement l'implémentation interne de la classe. Par conséquent, nous enveloppons les champs avec des propriétés (ou des méthodes dans le cas de Java) pour nous donner la possibilité de changer l'implémentation sans casser le code selon nous. Voir que nous pouvons mettre de la logique dans la propriété nous permet également d'effectuer une logique de validation, etc. si nous en avons besoin. C # 3 a la notion peut-être confuse d'auto-propriétés. Cela nous permet de définir simplement la propriété et le compilateur C # 3 générera le champ privé pour nous.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}

89
+1 pour mentionner les propriétés immobilières - je pense que c'est quelque chose que beaucoup de réponses ici (et ailleurs) ont oublié d'apporter. Sans cette explication, il peut encore être assez difficile de comprendre ce public int myVar { get; set; }qui représente vraiment (et je suppose que c'est la raison pour au moins 50% des hits de cette question).
Priidu Neemre

7
+1 également pour avoir mentionné l'automobile et pour avoir expliqué comment cela fonctionne ("AutoProperty génère un champ privé pour nous"). C'est la réponse que je cherchais à une question que j'avais. Lors de mes recherches, je n'ai vu sur la page MSDN à leur sujet aucune indication qu'un champ privé avait été créé et causait de la confusion. Je suppose que c'est ce que cela signifie? "Les attributs sont autorisés sur les propriétés implémentées automatiquement, mais évidemment pas sur les champs de support car ils ne sont pas accessibles à partir de votre code source. Si vous devez utiliser un attribut sur le champ de support d'une propriété, créez simplement une propriété régulière." mais je n'en étais pas sûr.
Nyra

3
Notez que l'exemple donné n'encapsule pas le squat. Cette propriété donne un accès complet à 100% au champ privé, donc ce n'est pas du tout orienté objet. Vous pourriez aussi bien avoir un domaine public dans ce cas. Certes, cela aide (marginalement) à refactoriser le code à l'avenir, mais tout IDE qui en vaut la peine peut transformer un champ en une propriété en quelques touches. La réponse peut être techniquement correcte sur le fonctionnement des propriétés, mais elle ne donne pas une bonne "explication de POO" à leurs utilisations.
sara

2
@kai Je suis d'accord pour dire que la réponse simplifie trop les choses et ne montre pas toute la puissance d'une auto-propriété, mais je ne suis pas d'accord pour dire que ce n'est pas orienté objet. Vous voudrez peut-être vérifier la différence entre les champs et les propriétés . Les champs ne peuvent pas être virtuels et font eux- virtualmêmes partie de la programmation orientée objet.
Gobe

Certes, il existe des différences fonctionnelles. Je n'appellerais pas virtualOOP en soi cependant. C'est un outil qui permet le polymorphisme, qui est l'un des outils clés qui PERMET LA POO. Ce n'est cependant pas une POO en soi, et il n'y a rien de intrinsèquement POO dans une propriété publique. Je ne compterais pas non plus des choses comme la réflexion ou la liaison de données OOP. Normalement, je ne serais pas aussi pédant à ce sujet, mais la réponse mentionnait spécifiquement les principes OO comme moteur de l'exemple de code, et je ne suis pas d'accord avec cela.
sara

164

Une différence importante est que les interfaces peuvent avoir des propriétés mais pas des champs. Cela, pour moi, souligne que les propriétés doivent être utilisées pour définir l'interface publique d'une classe alors que les champs sont destinés à être utilisés dans le fonctionnement interne privé d'une classe. En règle générale, je crée rarement des champs publics et, de même, je crée rarement des propriétés non publiques.


98

Je vais vous donner quelques exemples d'utilisation de propriétés qui pourraient faire tourner les engrenages:

  • Initialisation paresseuse : si vous avez une propriété d'un objet qui est cher à charger, mais qui n'est pas beaucoup accessible dans les exécutions normales du code, vous pouvez retarder son chargement via la propriété. De cette façon, il est juste assis là, mais la première fois qu'un autre module essaie d'appeler cette propriété, il vérifie si le champ sous-jacent est nul - s'il l'est, il continue et le charge, à l'insu du module appelant. Cela peut accélérer considérablement l'initialisation des objets.
  • Dirty Tracking: ce que j'ai appris de ma propre question ici sur StackOverflow. Lorsque j'ai beaucoup d'objets dont les valeurs peuvent avoir changé au cours d'une exécution, je peux utiliser la propriété pour suivre s'ils doivent être sauvegardés dans la base de données ou non. Si aucune propriété d'un objet n'a changé, l'indicateur IsDirty ne sera pas déclenché, et donc la fonctionnalité d'enregistrement l'ignorera lors de la décision de ce qui doit revenir à la base de données.

1
Une question sur le suivi sale: et si je pouvais changer le champ directement - je ne sais pas si cela peut être fait, je pourrais dire: "l'objet n'a pas besoin d'être enregistré si pas un seul CHAMP d'un objet a changé" un suivi aussi sale ne ferait pas de différence, ai-je raté quelque chose?
sites

2
@juanpastas: L'avantage des propriétés en ce qui concerne le suivi sale est que si les évaluateurs de propriétés définissent un indicateur "sale", alors dans le scénario où l'indicateur n'est pas défini, le code n'aura pas à inspecter les valeurs des propriétés pour voir s'ils auraient pu changer. En revanche, si un objet expose ses attributs en tant que champs, le contenu de tous les champs doit être comparé à la valeur précédente (ce qui non seulement ajoute du temps pour effectuer la comparaison, mais signifie également que le code doit avoir la valeur précédente).
supercat

Celles-ci sont bonnes. Elle vous permet également de déclencher des méthodes (en tant qu'événements) ou de vous connecter lorsque la valeur est définie ou lue.
coloboxp

54

En utilisant Propriétés, vous pouvez déclencher un événement, lorsque la valeur de la propriété est modifiée (alias. PropertyChangedEvent) ou avant que la valeur ne soit modifiée pour prendre en charge l'annulation.

Cela n'est pas possible avec (accès direct aux) champs.

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}

3
J'ai mis beaucoup de temps à trouver ça. Il s'agit d'un MVVM . Merci ! :)

46

Étant donné que beaucoup d'entre eux ont expliqué les avantages et les inconvénients techniques de Propertieset Field, il est temps d'entrer dans des exemples en temps réel.

1. Propriétés vous permet de définir le niveau d'accès en lecture seule

Prenons le cas de dataTable.Rows.Countet dataTable.Columns[i].Caption. Ils viennent de la classe DataTableet nous sont tous les deux publics. La différence dans le niveau d'accès pour eux est que nous ne pouvons pas définir de valeur dataTable.Rows.Countmais que nous pouvons lire et écrire dataTable.Columns[i].Caption. Est-ce possible grâce à Field? Non!!! Cela ne peut être fait qu'avec Properties.

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. Propriétés dans PropertyGrid

Vous avez peut-être travaillé avec Buttondans Visual Studio. Ses propriétés sont affichées de la PropertyGridmême manière Text, Nameetc. Lorsque nous glissons et déposons un bouton, et lorsque nous cliquons sur les propriétés, il trouvera automatiquement la classe Buttonet les filtres Propertieset le montrera dans PropertyGrid(où PropertyGridne s'affichera pas Fieldmême s'ils sont publics).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

Dans PropertyGrid, les propriétés Nameet Textseront affichées, mais pas SomeProperty. Pourquoi??? Parce que les propriétés peuvent accepter des attributs . Il ne s'affiche pas dans le cas où [Browsable(false)]est faux.

3. Peut exécuter des instructions à l'intérieur des propriétés

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4. Seules les propriétés peuvent être utilisées dans la source de liaison

Binding Source nous aide à diminuer le nombre de lignes de code. Fieldsne sont pas acceptés par BindingSource. Nous devrions utiliser Propertiespour cela.

5. Mode de débogage

Considérez que nous utilisons Fieldpour conserver une valeur. À un moment donné, nous devons déboguer et vérifier où la valeur devient nulle pour ce champ. Il sera difficile de le faire lorsque le nombre de lignes de code est supérieur à 1000. Dans de telles situations, nous pouvons utiliser Propertyet définir le mode de débogage à l'intérieur Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }

Ce sont des faits intéressants, mais vous manquez la philosophie des champs et des propriétés.
David Ferenczy Rogožan

Que voulez-vous dire par PHILISOPHIE ? @Dawid Ferenczy
Sarath Avanavu

Voir par exemple la réponse marquée. Mais vous avez remarqué que vous fournissez simplement des exemples d'utilisation, car la différence entre les champs et les propriétés a déjà été décrite, alors j'ai oublié mon commentaire, s'il vous plaît :)
David Ferenczy Rogožan

2
Lisez ma première phrase dans ma réponse. J'ai dit spécifiquement que je ne vais pas tout répéter ici. Ça n'a aucun sens!!! Les gens vont d'abord regarder la description, puis les exemples. La réponse marquée donne bien la description, mais j'ai ajouté avec quelques scénarios et exemples en temps réel qui ont du sens. Assurez-vous de réfléchir du point de vue du lecteur avant de commenter @Dawid Ferenczy
Sarath Avanavu

1
Je l'ai lu, mais vous n'avez évidemment pas lu mon commentaire précédent: " Mais vous avez remarqué que vous fournissez simplement des exemples d'utilisation, car la différence entre les champs et les propriétés a déjà été décrite, alors j'ai oublié mon commentaire, s'il vous plaît :) " .
David Ferenczy Rogožan

32

DIFFÉRENCES - UTILISATIONS (quand et pourquoi)

Un champ est une variable qui est déclarée directement dans une classe ou une structure. Une classe ou une structure peut avoir des champs d'instance ou des champs statiques ou les deux. En règle générale, vous devez utiliser les champs uniquement pour les variables qui ont une accessibilité privée ou protégée . Les données que votre classe expose au code client doivent être fournies via des méthodes, des propriétés et des indexeurs. En utilisant ces constructions pour un accès indirect aux champs internes, vous pouvez vous prémunir contre les valeurs d'entrée non valides.

Une propriété est un membre qui fournit un mécanisme flexible pour lire, écrire ou calculer la valeur d'un champ privé. Les propriétés peuvent être utilisées comme si elles étaient des membres de données publiques, mais ce sont en fait des méthodes spéciales appelées accesseurs . Cela permet d'accéder facilement aux données tout en favorisant la sécurité et la flexibilité des méthodes . Les propriétés permettent à une classe d'exposer une manière publique d'obtenir et de définir des valeurs, tout en masquant le code d'implémentation ou de vérification. Un accesseur de propriété get est utilisé pour renvoyer la valeur de la propriété et un accesseur set est utilisé pour affecter une nouvelle valeur.


Ceci est une réponse impressionnante, m'a vraiment aidé à comprendre cela.
Steve Bauman

14

Les propriétés ont le principal avantage de vous permettre de modifier la façon dont les données sur un objet sont accessibles sans casser son interface publique. Par exemple, si vous devez ajouter une validation supplémentaire ou changer un champ stocké en un champ calculé, vous pouvez le faire facilement si vous avez initialement exposé le champ en tant que propriété. Si vous venez d'exposer un champ directement, vous devrez modifier l'interface publique de votre classe pour ajouter la nouvelle fonctionnalité. Ce changement briserait les clients existants, les obligeant à être recompilés avant de pouvoir utiliser la nouvelle version de votre code.

Si vous écrivez une bibliothèque de classes conçue pour une large consommation (comme le .NET Framework, qui est utilisé par des millions de personnes), cela peut être un problème. Cependant, si vous écrivez une classe utilisée en interne dans une petite base de code (disons <= 50 K lignes), ce n'est vraiment pas un gros problème, car personne ne serait affecté négativement par vos modifications. Dans ce cas, cela se résume vraiment à des préférences personnelles.


11

Les propriétés prennent en charge l'accès asymétrique, c'est-à-dire que vous pouvez avoir un getter et un setter ou juste l'un des deux. De même, les propriétés prennent en charge l'accessibilité individuelle pour getter / setter. Les champs sont toujours symétriques, c'est-à-dire que vous pouvez toujours obtenir et définir la valeur. Une exception à cela est les champs en lecture seule qui ne peuvent évidemment pas être définis après l'initialisation.

Les propriétés peuvent s'exécuter très longtemps, avoir des effets secondaires et même lever des exceptions. Les champs sont rapides, sans effets secondaires et ne lèveront jamais d'exceptions. En raison des effets secondaires, une propriété peut renvoyer une valeur différente pour chaque appel (comme cela peut être le cas pour DateTime.Now, c'est-à-dire que DateTime.Now n'est pas toujours égal à DateTime.Now). Les champs renvoient toujours la même valeur.

Les champs peuvent être utilisés pour les paramètres out / ref, pas les propriétés. Les propriétés prennent en charge une logique supplémentaire - cela pourrait être utilisé pour implémenter le chargement différé, entre autres.

Les propriétés prennent en charge un niveau d'abstraction en encapsulant ce que cela signifie pour obtenir / définir la valeur.

Utilisez des propriétés dans la plupart / tous les cas, mais essayez d'éviter les effets secondaires.


Les champs peuvent avoir tous les problèmes de coût des propriétés lorsque le type de données du champ est un objet avec une surcharge d'opérateur de conversion - c'est un piège subtil.
Andy Dent

1
Les propriétés ne devraient jamais avoir d'effets secondaires. Même le débogueur suppose qu'il peut les évaluer en toute sécurité.
Craig Gidney

@Strilanc: Je suis entièrement d'accord, cependant, ce n'est pas toujours le cas. Quant au débogueur, il y a beaucoup de problèmes avec FuncEval si c'est ce dont vous parlez.
Brian Rasmussen

11

En arrière-plan, une propriété est compilée en méthodes. Une Namepropriété est donc compilée dans get_Name()et set_Name(string value). Vous pouvez le voir si vous étudiez le code compilé. Il y a donc une (très) petite surcharge de performances lors de leur utilisation. Normalement, vous utiliserez toujours une propriété si vous exposez un champ à l'extérieur, et vous l'utiliserez souvent en interne si vous avez besoin de valider la valeur.


7

Lorsque vous souhaitez que votre variable privée (champ) soit accessible à l'objet de votre classe à partir d'autres classes, vous devez créer des propriétés pour ces variables.

par exemple, si j'ai des variables nommées "id" et "name" qui sont privées, mais il peut y avoir une situation où cette variable est nécessaire pour une opération de lecture / écriture en dehors de la classe. Dans cette situation, la propriété peut m'aider à obtenir cette variable en lecture / écriture en fonction du get / set défini pour la propriété. Une propriété peut être à la fois en lecture seule / écriture seule / lecture seule.

voici la démo

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}

6

La deuxième question ici, "quand faut-il utiliser un champ au lieu d'une propriété?", N'est que brièvement abordée dans cette autre réponse et un peu celle-ci aussi , mais pas vraiment beaucoup de détails.

En général, toutes les autres réponses sont précises sur une bonne conception: préférez exposer les propriétés plutôt que d'exposer les champs. Bien que vous ne vous trouviez probablement pas régulièrement en train de dire "wow, imaginez à quel point les choses seraient pires si j'avais fait de ce champ un lieu de propriété", il est tellement plus rare de penser à une situation où vous diriez "wow, Dieu merci, j'ai utilisé un champ ici au lieu d'une propriété. "

Mais les champs ont un avantage sur les propriétés, et c'est leur capacité à être utilisés comme paramètres "ref" / "out". Supposons que vous ayez une méthode avec la signature suivante:

public void TransformPoint(ref double x, ref double y);

et supposez que vous souhaitez utiliser cette méthode pour transformer un tableau créé comme ceci:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

Voici, je pense, le moyen le plus rapide de le faire, car X et Y sont des propriétés:

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

Et ça va être plutôt bien! Sauf si vous avez des mesures qui prouvent le contraire, il n'y a aucune raison de jeter une odeur. Mais je pense qu'il n'est pas techniquement garanti d'être aussi rapide que cela:

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

En faisant moi-même quelques mesures , la version avec champs prend environ 61% du temps comme version avec propriétés (.NET 4.6, Windows 7, x64, mode de publication, aucun débogueur attaché). Plus la TransformPointméthode est coûteuse , moins la différence est prononcée. Pour répéter cela vous-même, exécutez avec la première ligne commentée et avec elle non commentée.

Même s'il n'y avait aucun avantage en termes de performances pour ce qui précède, il existe d'autres endroits où la possibilité d'utiliser des paramètres ref et out peut être bénéfique, comme lors de l'appel de la famille de méthodes Interlocked ou Volatile . Remarque: dans le cas où cela est nouveau pour vous, Volatile est essentiellement un moyen d'obtenir le même comportement que celui fourni par le volatilemot - clé. En tant que tel, comme volatile, il ne résout pas comme par magie tous les problèmes de sécurité des threads, comme son nom l'indique.

Je ne veux vraiment pas donner l'impression que je préconise que vous disiez "oh, je devrais commencer à exposer des champs plutôt que des propriétés". Le fait est que si vous devez utiliser régulièrement ces membres dans des appels qui prennent des paramètres "ref" ou "out", en particulier sur quelque chose qui pourrait être un type de valeur simple qui n'aura probablement jamais besoin des éléments à valeur ajoutée des propriétés, un argument peut être avancé.


6

Bien que les champs et les propriétés semblent similaires, ce sont deux éléments de langage complètement différents.

  1. Les champs sont le seul mécanisme permettant de stocker des données au niveau de la classe. Les champs sont conceptuellement des variables au niveau de la classe. Si vous souhaitez stocker des données dans des instances de vos classes (objets), vous devez utiliser des champs. Il n'y a pas d'autre choix. Les propriétés ne peuvent pas stocker de données même si elles semblent pouvoir le faire. Voir ci-dessous.

  2. En revanche, les propriétés ne stockent jamais de données. Ce ne sont que les paires de méthodes (get et set) qui peuvent être appelées syntaxiquement de la même manière que les champs et dans la plupart des cas, elles accèdent (pour la lecture ou l'écriture) aux champs, ce qui est source de confusion. Mais comme les méthodes de propriété sont (avec quelques limitations comme le prototype fixe) des méthodes C # régulières, elles peuvent faire tout ce que les méthodes régulières peuvent faire. Cela signifie qu'ils peuvent avoir 1000 lignes de code, ils peuvent lever des exceptions, appeler d'autres méthodes, peuvent même être virtuels, abstraits ou remplacés. Ce qui rend les propriétés spéciales, c'est le fait que le compilateur C # stocke des métadonnées supplémentaires dans des assemblys qui peuvent être utilisés pour rechercher des propriétés spécifiques - fonctionnalité largement utilisée.

Les méthodes d'obtention et de définition des propriétés comportent les prototypes suivants.

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

Cela signifie donc que les propriétés peuvent être «émulées» en définissant un champ et 2 méthodes correspondantes.

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

Une telle émulation de propriété est typique des langages de programmation qui ne prennent pas en charge les propriétés, comme le C ++ standard. En C #, vous devriez toujours préférer les propriétés comme moyen d'accéder à vos champs.

Étant donné que seuls les champs peuvent stocker des données, cela signifie que plus de classe de champs contient, plus d'objets mémoire de cette classe consommeront. D'un autre côté, l'ajout de nouvelles propriétés dans une classe n'agrandit pas les objets de cette classe. Voici l'exemple.

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

Bien que les méthodes de propriété puissent tout faire, dans la plupart des cas, elles permettent d'accéder aux champs des objets. Si vous souhaitez rendre un champ accessible à d'autres classes, vous pouvez le faire de 2 manières.

  1. Rendre les champs publics - déconseillé.
  2. Utilisation des propriétés.

Voici une classe utilisant des champs publics.

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

Bien que le code soit parfaitement valide, du point de vue de la conception, il présente plusieurs inconvénients. Étant donné que les champs peuvent être à la fois lus et écrits, vous ne pouvez pas empêcher l'utilisateur d'écrire dans les champs. Vous pouvez appliquer un readonlymot clé, mais de cette manière, vous devez initialiser les champs en lecture seule uniquement dans le constructeur. De plus, rien ne vous empêche de stocker des valeurs invalides dans vos champs.

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

Le code est valide, toutes les affectations seront exécutées bien qu'elles soient illogiques. Agea une valeur négative, YearOfBirthest loin dans le futur et ne correspond pas à l'âge et FullNameest nul. Avec les champs, vous ne pouvez pas empêcher les utilisateurs de class Namefaire de telles erreurs.

Voici un code avec des propriétés qui corrige ces problèmes.

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

La version mise à jour de la classe présente les avantages suivants.

  1. FullName et YearOfBirth sont vérifiés pour les valeurs non valides.
  2. Agen'est pas inscriptible. Il est calculé à partir deYearOfBirth l'année en cours.
  3. Une nouvelle propriété est FullNameInUppercaseconvertie FullNameen MAJUSCULE. Ceci est un petit exemple artificiel d'utilisation des propriétés, où les propriétés sont couramment utilisées pour présenter les valeurs de champ dans le format qui convient le mieux à l'utilisateur - par exemple en utilisant les paramètres régionaux actuels sur un DateTimeformat numérique spécifique .

À côté de cela, les propriétés peuvent être définies comme virtuelles ou remplacées - simplement parce que ce sont des méthodes .NET normales. Les mêmes règles s'appliquent pour ces méthodes de propriété que pour les méthodes normales.

C # prend également en charge les indexeurs qui sont les propriétés qui ont un paramètre d'index dans les méthodes de propriété. Voici l'exemple.

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

Depuis C # 3.0 vous permet de définir des propriétés automatiques. Voici l'exemple.

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

Même s'il class AutoPropsne contient que des propriétés (ou il ressemble), il peut stocker 2 valeurs et la taille des objets de cette classe est égale àsizeof(Value1)+sizeof(Value2) = 4 + 4 = 8 octets.

La raison en est simple. Lorsque vous définissez une propriété automatique, le compilateur C # génère du code automatique qui contient un champ masqué et une propriété avec des méthodes de propriété accédant à ce champ masqué. Voici le compilateur de code produit.

Voici un code généré par l' ILSpy à partir d'un assemblage compilé. La classe contient les champs et propriétés masqués générés.

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

Ainsi, comme vous pouvez le voir, le compilateur utilise toujours les champs pour stocker les valeurs - car les champs sont le seul moyen de stocker des valeurs dans des objets.

Donc, comme vous pouvez le voir, bien que les propriétés et les champs aient une syntaxe d'utilisation similaire, ce sont des concepts très différents.Même si vous utilisez des propriétés ou des événements automatiques - les champs masqués sont générés par le compilateur où les données réelles sont stockées.

Si vous devez rendre une valeur de champ accessible au monde extérieur (utilisateurs de votre classe), n'utilisez pas de champs publics ou protégés. Les champs doivent toujours être marqués comme privés. Les propriétés vous permettent d'effectuer des vérifications de valeurs, de formatage, de conversions, etc. et rendent généralement votre code plus sûr, plus lisible et plus extensible pour de futures modifications.


4

De plus, les propriétés vous permettent d'utiliser la logique lors de la définition des valeurs.

Vous pouvez donc dire que vous ne souhaitez définir une valeur que dans un champ entier, si la valeur est supérieure à x, sinon, lève une exception.

Fonction vraiment utile.


4

Si vous allez utiliser des primitives de threads, vous êtes obligé d'utiliser des champs. Les propriétés peuvent casser votre code fileté. En dehors de cela, ce que Cory a dit est correct.


1
depuis quand? verrouillez votre terrain de support au sein de la propriété et c'est l'équivalent
Sekhat

1
Les propriétés sont des méthodes et ne sont pas intégrées par aucun CIL JIT aujourd'hui. Si vous allez utiliser des primitives de thread comme Interlocked, vous devez avoir des champs. Vérifiez vos sources. Certes, «verrouiller» n'était pas le bon mot à utiliser.
Jonathan C Dickinson

4

(Cela devrait vraiment être un commentaire, mais je ne peux pas poster de commentaire, veuillez donc excuser s'il ne convient pas en tant que message).

J'ai déjà travaillé dans un endroit où la pratique recommandée était d'utiliser des champs publics au lieu de propriétés lorsque la propriété équivalente def aurait simplement accédé à un champ, comme dans:

get { return _afield; }
set { _afield = value; }

Leur raisonnement était que le domaine public pourrait être converti en propriété plus tard à l'avenir si nécessaire. Cela me semblait un peu étrange à l'époque. À en juger par ces messages, il semble que peu de gens ici seraient d'accord non plus. Qu'auriez-vous pu dire pour essayer de changer les choses?

Edit: je devrais ajouter que toute la base de code à cet endroit a été compilée en même temps, donc ils auraient pu penser que changer l'interface publique des classes (en changeant un champ public en propriété) n'était pas un problème.


Depuis C # 3.0 , le modèle décrit ici est commodément pris en charge par une fonctionnalité appelée Propriétés implémentées automatiquement .
DavidRR

Je pense que l'un des avantages de C # avec des propriétés car ils ont la même API que les champs, donc les clients de la classe ne se soucient pas vraiment s'ils accèdent à une propriété ou à un champ. (Ce n'est PAS vrai en C ++ par exemple). En prototypage, je pense qu'il est raisonnable de commencer par les champs publics, puis de migrer vers les propriétés selon les besoins. Il y a un impact sur les performances et la mémoire avec des propriétés, et il y a une frappe supplémentaire. Ils ne sont pas gratuits. Mais, si vous changez d'avis, vous n'aurez pas besoin de refactoriser un code dépendant.
Mark Lakata

Les propriétés ne peuvent pas être utilisées comme paramètres OUT ou REF, donc la modification d'un champ en propriété peut entraîner des erreurs de compilation sur toute la ligne. Si la valeur a été implémentée en tant que propriété depuis le début, elle n'aurait jamais été utilisée comme paramètres OUT ou REF (VAR en Pascal / Delphi), et toute modification que vous apportez dans le getter / setter serait transparente pour l'utilisation.
HeartWare

4

Techniquement, je ne pense pas qu'il y ait de différence, car les propriétés ne sont que des wrappers autour des champs créés par l'utilisateur ou automatiquement créés par le compilateur.Le but des propriétés est d'imposer l'encapsulation et d'offrir une fonctionnalité légère de type méthode. C'est juste une mauvaise pratique de déclarer des champs publics, mais cela ne pose aucun problème.


4

Les champs sont des variables membres ordinaires ou des instances membres d'une classe. Les propriétés sont une abstraction pour obtenir et définir leurs valeurs . Les propriétés sont également appelées accesseurs car elles offrent un moyen de modifier et de récupérer un champ si vous exposez un champ de la classe comme privé. En règle générale, vous devez déclarer vos variables membres privées, puis déclarer ou définir des propriétés pour elles.

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }

3

Les propriétés encapsulent les champs, vous permettant ainsi d'effectuer un traitement supplémentaire sur la valeur à définir ou à récupérer. Il est généralement exagéré d'utiliser des propriétés si vous n'effectuez aucun prétraitement ou post-traitement sur la valeur du champ.


1
non, j'utilise toujours des propriétés, cela vous permet de changer l'implémentation à tout moment sans casser votre API.
Sekhat

Concernant l'évolution de l'API, vous pouvez utiliser des champs pour les données privées sans problème. Dans les cas étranges où vous souhaitez partager des données au sein d'un assemblage, vous pouvez également donner aux champs un accès «interne».
Daniel Earwicker

3

OMI, les propriétés ne sont que les paires fonctions / méthodes / interfaces "SetXXX ()" "GetXXX ()" que nous avons utilisées auparavant, mais elles sont plus concises et élégantes.


3

Les champs traditionnellement privés sont définis via les méthodes getter et setter. Pour réduire le code, vous pouvez utiliser des propriétés pour définir des champs à la place.


3

lorsque vous avez une classe qui est "Car". Les propriétés sont la couleur, la forme ..

Alors que les champs sont des variables définies dans le cadre d'une classe.


3

De Wikipedia - Programmation orientée objet :

La programmation orientée objet (POO) est un paradigme de programmation basé sur le concept des "objets", qui sont des structures de données qui contiennent des données, sous la forme de champs , souvent appelés attributs; et du code, sous forme de procédures, souvent appelées méthodes . (pas d'italique dans l'original)

Les propriétés font en fait partie du comportement d'un objet, mais sont conçues pour donner aux consommateurs de l'objet l'illusion / l'abstraction de travailler avec les données de l'objet.


3

Ma conception d'un champ est qu'un champ doit être modifié uniquement par son parent, d'où la classe. Résultat la variable devient privée, puis pour pouvoir donner le droit de lire les classes / méthodes en dehors je passe par le système de propriété avec seulement le Get. Le champ est ensuite récupéré par la propriété et en lecture seule! Si vous voulez le modifier, vous devez passer par des méthodes (par exemple le constructeur) et je trouve que grâce à cette façon de vous sécuriser, nous avons un meilleur contrôle sur notre code parce que nous "flange". On pourrait très bien toujours tout mettre en public donc tous les cas possibles, la notion de variables / méthodes / classes etc ... à mon avis n'est qu'une aide au développement, à la maintenance du code. Par exemple, si une personne reprend un code avec des champs publics, elle peut faire n'importe quoi et donc des choses "illogiques" par rapport à l'objectif, la logique de la raison pour laquelle le code a été écrit. C'est mon point de vue.

Lorsque j'utilise un champ privé de modèle classique / des propriétés publiques en lecture seule, pour 10 champs privés, je dois écrire 10 propriétés publiques! Le code peut être vraiment gros plus rapidement. Je découvre le setter privé et maintenant je n'utilise que les propriétés publiques avec un setter privé. Le setter crée en arrière-plan un champ privé.

C'est pourquoi mon ancien style de programmation classique était:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

Mon nouveau style de programmation:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}

Ouais mon mauvais, désolé!
Tony Pinot

3

Pensez-y: vous avez une chambre et une porte pour y entrer. Si vous voulez vérifier comment qui entre et sécuriser votre chambre, vous devez utiliser les propriétés sinon elles ne seront pas une porte et chacune entrera facilement sans aucune réglementation

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

Les gens entrent dans la section Un facilement, il n'y a pas eu de vérification

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

Maintenant, vous avez vérifié la personne et savez s'il a quelque chose de mal avec lui


3

Les champs sont les variables des classes. Les champs sont les données que vous pouvez encapsuler grâce à l'utilisation de modificateurs d'accès.

Les propriétés sont similaires aux champs dans la mesure où elles définissent les états et les données associées à un objet.

Contrairement à un champ, une propriété a une syntaxe spéciale qui contrôle la façon dont une personne lit les données et écrit les données, ce sont les opérateurs get et set. La logique définie peut souvent être utilisée pour effectuer la validation.


2

Les propriétés sont un type spécial de membre de classe. Dans les propriétés, nous utilisons une méthode Set ou Get prédéfinie. Ils utilisent des accesseurs à travers lesquels nous pouvons lire, écrire ou modifier les valeurs des champs privés.

Par exemple, prenons une classe nommée Employee, avec des champs privés pour name, age et Employee_Id. Nous ne pouvons pas accéder à ces champs depuis l'extérieur de la classe, mais nous pouvons accéder à ces champs privés via des propriétés.

Pourquoi utilisons-nous des propriétés?

Rendre le champ de classe public et l'exposer est risqué, car vous n'aurez aucun contrôle sur ce qui est attribué et retourné.

Pour comprendre cela clairement avec un exemple, prenons une classe d'élève qui a une ID, un mot de passe, un nom. Maintenant, dans cet exemple, un problème avec le domaine public

  • L'ID ne doit pas être -ve.
  • Le nom ne peut pas être défini sur null
  • La note de passage doit être en lecture seule.
  • Si le nom de l'élève est manquant, aucun nom ne doit être renvoyé.

Pour supprimer ce problème, nous utilisons la méthode Get et set.

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

Maintenant, prenons un exemple de méthode get et set

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}

2

Informations supplémentaires: Par défaut, les accesseurs get et set sont aussi accessibles que la propriété elle-même. Vous pouvez contrôler / restreindre l'accessibilité des accesseurs individuellement (pour obtenir et définir) en leur appliquant des modificateurs d'accès plus restrictifs.

Exemple:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

Ici, get est toujours accessible au public (car la propriété est publique), mais set est protégé (un spécificateur d'accès plus restreint).


2

Les propriétés sont utilisées pour exposer le champ. Ils utilisent des accesseurs (set, get) à travers lesquels les valeurs des champs privés peuvent être lues, écrites ou manipulées.

Les propriétés ne nomment pas les emplacements de stockage. Au lieu de cela, ils ont des accesseurs qui lisent, écrivent ou calculent leurs valeurs.

En utilisant des propriétés, nous pouvons définir la validation sur le type de données qui est défini sur un champ.

Par exemple, nous avons l'âge du champ entier privé sur lequel nous devons autoriser des valeurs positives car l'âge ne peut pas être négatif.

Nous pouvons le faire de deux manières en utilisant getter et setters et en utilisant property.

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

Propriété implémentée automatiquement Si nous ne faisons pas de logique dans les accesseurs get et set, nous pouvons utiliser la propriété implémentée automatiquement.

Lorsque vous compilez des propriétés implémentées automatiquement, un champ privé anonyme est accessible uniquement via les accesseurs get et set.

public int Age{get;set;}

Propriétés abstraites Une classe abstraite peut avoir une propriété abstraite, qui doit être implémentée dans la classe dérivée

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

Nous pouvons définir en privé une propriété Dans cela, nous pouvons définir en privé la propriété auto (définie avec dans la classe)

public int MyProperty
{
    get; private set;
}

Vous pouvez obtenir la même chose avec ce code. Dans ce jeu de propriétés, la fonctionnalité n'est pas disponible car nous devons définir la valeur directement dans le champ.

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

2

Dans la grande majorité des cas, ce sera un nom de propriété auquel vous accédez par opposition à un nom de variable ( champ ) La raison en est qu'il est considéré comme une bonne pratique dans .NET et en C # en particulier pour protéger chaque élément de données au sein d'une classe , qu'il s'agisse d'une variable d'instance ou d'une variable statique (variable de classe) car elle est associée à une classe.

Protégez toutes ces variables avec des propriétés correspondantes qui vous permettent de définir, définir et obtenir des accesseurs et de faire des choses comme la validation lorsque vous manipulez ces éléments de données.

Mais dans d'autres cas, comme la classe Math (espace de noms System), deux propriétés statiques sont intégrées à la classe. dont l'un est la constante mathématique PI

par exemple. Math.PI

et parce que PI est une donnée bien définie, nous n'avons pas besoin d'avoir plusieurs copies de PI, ce sera toujours la même valeur. Ainsi, les variables statiques sont parfois utilisées pour partager des données entre les objets d'une classe, mais elles sont également couramment utilisées pour des informations constantes où vous n'avez besoin que d'une copie d'un élément de données.

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.