Propriétés (Guide de programmation C#)
Une propriété est un membre qui fournit un mécanisme flexible pour lire, écrire ou calculer la valeur d’un champ de données. Les propriétés apparaissent comme des membres de données publics, mais elles sont implémentées comme des méthodes spéciales appelées accessors. Cette fonctionnalité permet aux appelants d’accéder facilement aux données tout en favorisant la sécurité et la flexibilité des données. La syntaxe des propriétés est une extension naturelle des champs. Un champ définit un emplacement de stockage :
public class Person
{
public string? FirstName;
// Omitted for brevity.
}
Propriétés implémentées automatiquement
Une définition de propriété contient les déclarations de l’accesseur get
, qui récupère la valeur de cette propriété, et de l’accesseur set
, qui assigne cette valeur :
public class Person
{
public string? FirstName { get; set; }
// Omitted for brevity.
}
L’exemple précédent montre une propriété implémentée automatiquement. Le compilateur génère un champ de support caché pour la propriété. Le compilateur implémente également le corps des accesseurs get
et set
. Tous les attributs sont appliqués à la propriété implémentée automatiquement. Vous pouvez appliquer l’attribut au champ de support généré par le compilateur en spécifiant le tag field:
sur l’attribut.
Vous pouvez initialiser une propriété à une valeur autre que la valeur par défaut en définissant une valeur après l’accolade fermante de la propriété. Vous pourriez préférer que la valeur initiale de la propriété FirstName
soit la chaîne vide plutôt que null
. Vous spécifieriez cela comme indiqué dans le code suivant :
public class Person
{
public string FirstName { get; set; } = string.Empty;
// Omitted for brevity.
}
Propriétés sauvegardées par le champ
En C# 13, vous pouvez ajouter une validation ou une autre logique dans l’accesseur pour une propriété à l’aide de la field
fonctionnalité d’aperçu du mot clé. Le field
mot clé accède au champ de stockage synthétisé du compilateur pour une propriété. Il vous permet d’écrire un accesseur de propriété sans déclarer explicitement un champ de stockage distinct.
public class Person
{
public string? FirstName
{
get;
set => field = value.Trim();
}
// Omitted for brevity.
}
Important
Le field
mot clé est une fonctionnalité d’aperçu en C# 13. Vous devez utiliser .NET 9 et définir votre <LangVersion>
élément preview
dans votre fichier projet afin d’utiliser le field
mot clé contextuel.
Vous devez être prudent à l’aide de la field
fonctionnalité de mot clé dans une classe qui a un champ nommé field
. Le nouveau field
mot clé ombre un champ nommé field
dans l’étendue d’un accesseur de propriété. Vous pouvez modifier le nom de la field
variable ou utiliser le @
jeton pour référencer l’identificateur field
en tant que @field
. Pour plus d’informations, lisez la spécification de fonctionnalité pour le field
mot clé.
Propriétés requises
L’exemple précédent permet à un appelant de créer un Person
en utilisant le constructeur par défaut, sans définir la propriété FirstName
. La propriété a changé de type pour devenir une chaîne nullable. À partir de C# 11, vous pouvez exiger que les appelants définissent une propriété :
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
// Omitted for brevity.
}
Le code précédent apporte deux modifications à la classe Person
. Tout d’abord, la déclaration de propriété FirstName
inclut le modificateur required
. Cela signifie que tout code qui crée un nouveau Person
doit définir cette propriété en utilisant un initialiseur d’objet. Deuxièmement, le constructeur qui prend un paramètre firstName
a l’attribut System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute. Cet attribut informe le compilateur que ce constructeur définit tous required
les membres. Les appelants utilisant ce constructeur ne sont pas tenus de définir les propriétés required
avec un initialiseur d’objet.
Important
Ne confondez pas required
avec non-nullable. Définir une required
propriété sur null
ou default
est valide. Si le type est non-nullable, comme string
dans ces exemples, le compilateur émet un avertissement.
var aPerson = new Person("John");
aPerson = new Person{ FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();
Définitions de corps d’expression
Les accesseurs de propriété consistent souvent en des instructions sur une seule ligne. Les accesseurs assignent ou retournent le résultat d’une expression. Vous pouvez implémenter ces propriétés en tant que membres expression-bodied. Les définitions de corps d’expression consistent en le jeton =>
suivi de l’expression à assigner ou à récupérer de la propriété.
Les propriétés en lecture seule peuvent implémenter l’accesseur get
en tant que membre expression-bodied. L’exemple suivant implémente la propriété Name
en lecture seule comme un membre au corps d’expression :
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public required string FirstName { get; init; }
public required string LastName { get; init; }
public string Name => $"{FirstName} {LastName}";
// Omitted for brevity.
}
La propriété Name
est une propriété calculée. Il n’y a pas de champ de support pour Name
. La propriété le calcule à chaque fois.
Contrôle d’accès
Les exemples précédents montraient des propriétés en lecture/écriture. Vous pouvez également créer des propriétés en lecture seule ou donner une accessibilité différente aux accesseurs set et get. Supposons que votre Person
classe ne doit activer que la modification de la valeur de la FirstName
propriété à partir d’autres méthodes de la classe. Vous pouvez donner à l’accesseur private
défini l’accessibilité au lieu de internal
:public
public class Person
{
public string? FirstName { get; private set; }
// Omitted for brevity.
}
La propriété FirstName
peut être lue par n’importe quel code, mais elle ne peut être assignée que par le code de la classe Person
.
Vous pouvez ajouter n’importe quel modificateur d’accès restrictif à l’accesseur set ou get. Un modificateur d’accès sur un accesseur individuel doit être plus restrictif que l’accès de la propriété. Le code précédent est légal parce que la propriété FirstName
est public
, mais l’accesseur set est private
. En revanche, vous ne pouvez pas déclarer une propriété private
avec un accesseur public
. Les propriétés peuvent également être déclarées comme protected
, internal
, protected internal
ou même private
.
Il existe deux modificateurs d’accès spéciaux pour les accesseurs set
:
- Un accesseur
set
peut avoirinit
comme modificateur d’accès. Cet accesseurset
ne peut être appelé que par un initialiseur d’objet ou par les constructeurs du type. C’est plus restrictif queprivate
sur l’accesseurset
. - Une propriété implémentée automatiquement peut déclarer un
get
accesseur sansset
accesseur. Dans ce cas, le compilateur permet d’appeler l’accesseurset
uniquement à partir des constructeurs du type. C’est plus restrictif que l’accesseurinit
sur l’accesseurset
.
Modifiez la classe Person
comme suit :
public class Person
{
public Person(string firstName) => FirstName = firstName;
public string FirstName { get; }
// Omitted for brevity.
}
L’exemple précédent exige que les appelants utilisent le constructeur qui inclut le paramètre FirstName
. Les appelants ne peuvent pas utiliser d’initialiseurs d’objet pour affecter une valeur à la propriété. Pour prendre en charge les initialiseurs, vous pouvez faire de l’accesseur set
un accesseur init
, comme indiqué dans le code suivant :
public class Person
{
public Person() { }
public Person(string firstName) => FirstName = firstName;
public string? FirstName { get; init; }
// Omitted for brevity.
}
Ces modificateurs sont souvent utilisés avec le modificateur required
pour forcer une initialisation correcte.
Propriétés avec des champs de stockage
Vous pouvez mélanger le concept de propriété calculée avec un champ privé et créer une propriété évaluée en cache. Par exemple, mettez à jour la propriété FullName
pour que le formatage de la chaîne se fasse lors du premier accès :
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public required string FirstName { get; init; }
public required string LastName { get; init; }
private string? _fullName;
public string FullName
{
get
{
if (_fullName is null)
_fullName = $"{FirstName} {LastName}";
return _fullName;
}
}
}
Cette implémentation fonctionne parce que les propriétés FirstName
et LastName
sont en lecture seule. Les gens peuvent changer leur nom. La mise à jour des propriétés FirstName
et LastName
pour permettre l’accès aux accesseurs set
nécessite d’invalider toute valeur mise en cache pour fullName
. Vous modifiez les accesseurs set
des propriétés FirstName
et LastName
afin que le champ fullName
soit recalculé :
public class Person
{
private string? _firstName;
public string? FirstName
{
get => _firstName;
set
{
_firstName = value;
_fullName = null;
}
}
private string? _lastName;
public string? LastName
{
get => _lastName;
set
{
_lastName = value;
_fullName = null;
}
}
private string? _fullName;
public string FullName
{
get
{
if (_fullName is null)
_fullName = $"{FirstName} {LastName}";
return _fullName;
}
}
}
Dans cette version finale du code, la propriété FullName
est évaluée uniquement si cela est nécessaire. La version précédemment calculée est utilisée si elle est valide. Sinon, le calcul met à jour la valeur mise en cache. Les développeurs utilisant cette classe n’ont pas besoin de connaître les détails de l’implémentation. Ces modifications internes n’ont pas d’impact sur l’utilisation de l’objet Person.
À partir de C# 13, vous pouvez créer des propriétés partial
dans des classes partial
. La déclaration d’implémentation d’une partial
propriété ne peut pas être une propriété implémentée automatiquement. Une propriété implémentée automatiquement utilise la même syntaxe qu’une déclaration de propriété partielle.
Propriétés
Les propriétés sont une forme de champs intelligents dans une classe ou un objet. De l’extérieur de l’objet, elles apparaissent sous la forme de champs dans l’objet. Toutefois, les propriétés peuvent être implémentées avec toutes les fonctionnalités C#. Vous pouvez écrire du code qui remplit les exigences de validation, d’accessibilité, d’évaluation différée ou toute autre exigence requise dans vos scénarios.
- Les propriétés simples qui ne nécessitent aucun code d’accesseur personnalisé peuvent être implémentées en tant que définitions de corps d’expression ou en tant que propriétés implémentées automatiquement.
- Les propriétés permettent à une classe d'exposer un moyen public 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 retourner la valeur de la propriété et un accesseur de propriété set est utilisé pour affecter une nouvelle valeur. Un accesseur de propriété init est utilisé pour attribuer une nouvelle valeur uniquement pendant la construction d’objet. Ces accesseurs peuvent avoir différents niveaux d’accès. Pour plus d’informations, consultez Restriction d’accessibilité de l’accesseur.
- Le mot-clé valeur est utilisé pour définir la valeur le
set
ouinit
assignée par l'accesseur. - Les propriétés peuvent être en lecture-écriture (elles ont un accesseur
get
et un accesseurset
), en lecture seule (elles ont un accesseurget
, mais pas d’accesseurset
) ou en écriture seule (elles ont un accesseurset
, mais pas d’accesseurget
). Les propriétés en écriture seule sont rares.
Spécification du langage C#
Pour plus d’informations, consultez Propriétés dans la spécification du langage C#. La spécification du langage est la source de référence pour la syntaxe C# et son utilisation.