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


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


826


origine


Réponses:


Les propriétés exposent les champs. Les champs devraient (presque toujours) être gardés confidentiels dans une classe et accessibles via les propriétés get et set. Les propriétés fournissent un niveau d'abstraction qui vous permet de modifier les champs sans affecter la manière externe dont ils sont accédés par les éléments 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 requises pour encapsuler des champs, elles peuvent faire un calcul sur d'autres champs, ou servir à d'autres fins.

@GSS souligne que vous pouvez également faire d'autres logiques, telles que la validation, lorsqu'une propriété est accédée, une autre fonctionnalité utile.


741



Les principes de programmation orientés objet disent que le fonctionnement interne d'une classe doit être caché du monde extérieur. Si vous exposez un champ, vous exposerez 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 en fonction de nous. Voyant que nous pouvons mettre la logique dans la propriété nous permet également d'effectuer la logique de validation, etc., si nous en avons besoin. C # 3 a la notion potentiellement déroutante d'autoproperties. Cela nous permet de définir simplement la propriété et le compilateur C # 3 va générer 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
}

207



Une différence importante est que les interfaces peuvent avoir des propriétés mais pas des champs. Ceci, à mon sens, souligne que les propriétés devraient ê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.


126



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 que vous n'y avez pas accès 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 null - si c'est le cas, il le charge et le charge, inconnu du module appelant. Cela peut grandement accélérer l'initialisation de l'objet.
  • Dirty Tracking: Ce que j'ai réellement appris de mon propre question ici sur StackOverflow. Lorsque j'ai beaucoup d'objets dont les valeurs ont pu changer au cours d'une exécution, je peux utiliser la propriété pour savoir si elles doivent être sauvegardées dans la base de données ou non. Si aucune propriété d'un objet n'a été modifiée, l'indicateur IsDirty ne sera pas déclenché, et par conséquent la fonctionnalité d'enregistrement l'ignorera lorsqu'il décidera de ce qui doit revenir à la base de données.

85



En utilisant Propriétés, vous pouvez lancer 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.

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

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(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}

43



Comme beaucoup d'entre eux ont expliqué avec les avantages techniques et les inconvénients de Properties et 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

Considérons le cas de dataTable.Rows.Count et dataTable.Columns[i].Caption. Ils viennent de la classe DataTable et les deux sont publics pour nous. La différence dans le niveau d'accès à eux est que nous ne pouvons pas définir la valeur à dataTable.Rows.Count mais nous pouvons lire et écrire dataTable.Columns[i].Caption. Est-ce possible à travers Field? Non!!! Cela peut être fait avec Properties seulement.

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 Button dans Visual Studio. Ses propriétés sont montrées dans le PropertyGrid comme Text,Name etc. Lorsque nous faisons glisser et déposez un bouton, et lorsque nous cliquons sur les propriétés, il trouvera automatiquement la classe Button et filtres Properties et montrer que dans PropertyGrid (où PropertyGrid ne montrera pas Field même si elles sont publiques).

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 Name et Text sera montré, mais pas SomeProperty. Pourquoi??? Parce que les propriétés peuvent accepter Les attributs. Il n'apparaît pas dans le cas où [Browsable(false)] c'est faux.

3. Peut exécuter des instructions dans les 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

Source de liaison nous aide à diminuer le nombre de lignes de code. Fields ne sont pas acceptés par BindingSource. Nous devrions utiliser Properties pour ça.

5. Mode de débogage

Considérons que nous utilisons Field pour avoir une valeur. À un certain point, nous devons déboguer et vérifier où la valeur devient nulle pour ce champ. Il sera difficile de faire où le nombre de lignes de code est supérieur à 1000. Dans de telles situations, nous pouvons utiliser Property et peut 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;
        }
   }

36



DIFFERENCES - UTILISATIONS (quand et pourquoi)

UNE champ est une variable 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. Généralement, vous devriez utiliser des champs uniquement pour les variables ayant une accessibilité privée ou protégée. Données que votre classe expose au code client devrait être fourni par des méthodes, des propriétés et les indexeurs. En utilisant ces constructions pour l'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 des membres de données publiques, mais ce sont en réalité des méthodes spéciales appelées accesseurs. Cela permet d'accéder facilement aux données tout en contribuant à promouvoir sécurité et 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 l'implémentation ou le code de vérification. Un accesseur de propriété get est utilisé pour retourner la valeur de la propriété, et un accesseur set est utilisé pour assigner une nouvelle valeur.


21



Les propriétés ont l'avantage principal de vous permettre de changer la façon dont les données sur un objet sont accédées sans casser son interface publique. Par exemple, si vous devez ajouter une validation supplémentaire, ou pour convertir 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 directement un champ, vous devrez modifier l'interface publique de votre classe pour ajouter la nouvelle fonctionnalité. Ce changement casserait les clients existants, exigeant qu'ils soient recompilés avant qu'ils puissent 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 poser 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 une grosse affaire, car personne ne serait affecté par vos changements. Dans ce cas, il s'agit simplement d'une préférence personnelle.


9



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 le getter / setter. Les champs sont toujours symétriques, c'est-à-dire que vous pouvez toujours obtenir et définir la valeur. Une exception à ceci est les champs en lecture seule qui ne peuvent évidemment pas être définis après l'initialisation.

Les propriétés peuvent durer très longtemps, avoir des effets secondaires et même lancer des exceptions. Les champs sont rapides, sans effets secondaires et ne jetteront 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, les propriétés peuvent ne pas l'être. Les propriétés supportent la logique supplémentaire - ceci pourrait être utilisé pour implémenter le chargement différé entre autres choses.

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

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


7



En arrière-plan, une propriété est compilée en méthodes. Donc un Name la propriété est compilée dans get_Name() et set_Name(string value). Vous pouvez le voir si vous étudiez le code compilé. Il y a donc un (très) petit surcoût de performance 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