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é?
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é?
Réponses:
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.
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 string
en Surname
, alors leur nouvelle classe Surname communique les contraintes et la propriété public Surname LastName
n'a pas de validation setter. Aussi, Surname
est réutilisable.
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
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
}
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).
virtual
mêmes partie de la programmation orientée objet.
virtual
OOP 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.
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.
Je vais vous donner quelques exemples d'utilisation de propriétés qui pourraient faire tourner les engrenages:
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);
}
}
Étant donné que beaucoup d'entre eux ont expliqué les avantages et les inconvénients techniques 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
Prenons le cas de dataTable.Rows.Count
et dataTable.Columns[i].Caption
. Ils viennent de la classe DataTable
et 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.Count
mais 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 Button
dans Visual Studio. Ses propriétés sont affichées de la PropertyGrid
même manière Text
, Name
etc. Lorsque nous glissons et déposons un bouton, et lorsque nous cliquons sur les propriétés, il trouvera automatiquement la classe Button
et les filtres Properties
et le montrera dans PropertyGrid
(où PropertyGrid
ne s'affichera pas Field
mê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 Name
et Text
seront 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. Fields
ne sont pas acceptés par BindingSource
. Nous devrions utiliser Properties
pour cela.
5. Mode de débogage
Considérez que nous utilisons Field
pour 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 Property
et 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;
}
}
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.
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.
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.
En arrière-plan, une propriété est compilée en méthodes. Une Name
proprié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.
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";
}
}
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 TransformPoint
mé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 volatile
mot - 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é.
Bien que les champs et les propriétés semblent similaires, ce sont deux éléments de langage complètement différents.
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.
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.
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 readonly
mot 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. Age
a une valeur négative, YearOfBirth
est loin dans le futur et ne correspond pas à l'âge et FullName
est nul. Avec les champs, vous ne pouvez pas empêcher les utilisateurs de class Name
faire 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.
FullName
et YearOfBirth
sont vérifiés pour les valeurs non valides.Age
n'est pas inscriptible. Il est calculé à partir deYearOfBirth
l'année en cours.FullNameInUppercase
convertie FullName
en 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 DateTime
format 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 AutoProps
ne 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.
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.
(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.
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.
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;}
}
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.
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.
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.
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.
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.
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;
}
}
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
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.
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
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;
}
}
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).
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; }
}
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.