En C#, qu'est-ce qui différencie un champ d'une propriété, et quand faut-il utiliser un champ au lieu d'une propriété ?
Réponses
Trop de publicités?Les propriétés exposent les champs. Les champs doivent (presque toujours) rester privés pour une classe et être 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 tout en n'affectant pas la manière externe dont ils sont accessibles 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 you access it uses the underlying field, but only exposes
// the contract that will not be affected by the underlying field
public string MyField
{
get
{
return _myField;
}
set
{
_myField = value;
}
}
}
@Kent fait remarquer que les propriétés ne sont pas obligées d'encapsuler les champs, elles peuvent effectuer un calcul sur d'autres champs ou servir d'autres objectifs.
@GSS fait remarquer que vous pouvez également exécuter d'autres logiques, comme la validation, lors de l'accès à une propriété, ce qui constitue une autre fonctionnalité utile.
Les principes de la programmation orientée objet stipulent que le fonctionnement interne d'une classe doit être caché au monde extérieur. Si vous exposez un champ, vous exposez en fait l'implémentation interne de la classe. C'est pourquoi nous enveloppons les champs avec des propriétés (ou des méthodes dans le cas de Java) pour nous donner la possibilité de modifier l'implémentation sans casser le code qui dépend de nous. Le fait de pouvoir placer une logique dans la propriété nous permet également d'exécuter une logique de validation, etc. si nécessaire. Le C# 3 a la notion éventuellement déroutante d'autoproprié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
}
Une différence importante est que les interfaces peuvent avoir des propriétés mais pas des champs. Pour moi, cela souligne le fait que les propriétés doivent être utilisées pour définir l'interface publique d'une classe, tandis que les champs sont destinés à être utilisés dans le fonctionnement interne et 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 vous mettre la puce à l'oreille :
- Initialisation paresseuse : Si vous avez une propriété d'un objet qui est coûteux à charger, mais qui n'est pas accédé si souvent dans les exécutions normales du code, vous pouvez retarder son chargement via la propriété. De cette façon, elle reste 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 le charge, à l'insu du module appelant. Cela peut accélérer considérablement l'initialisation des objets.
- Sale traque : Ce que j'ai appris de mon 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 savoir s'ils doivent être sauvegardés 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 la fonctionnalité d'enregistrement passera donc outre lorsqu'il s'agira de décider ce qui doit être renvoyé dans la base de données.
À l'aide des propriétés, vous pouvez déclencher un événement lorsque la valeur de la propriété est modifiée (aka. PropertyChangedEvent) ou avant que la valeur ne soit modifiée pour permettre l'annulation.
Cela n'est pas possible avec les champs (accès direct).
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);
}
}
}
- Réponses précédentes
- Plus de réponses