Partager via


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é auto-implémentée. 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é auto-implémentée. 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.
}

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 classe Person doit uniquement autoriser la modification de la valeur de la propriété FirstName à partir des autres méthodes de cette classe. Vous pouvez alors assigner l’accessibilité private au lieu de public à l’accesseur set :

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 avoir init comme modificateur d’accès. Cet accesseur set ne peut être appelé que par un initialiseur d’objet ou par les constructeurs du type. C’est plus restrictif que private sur l’accesseur set.
  • Une propriété auto-implémentée peut déclarer un accesseur get sans accesseur set. Dans ce cas, le compilateur permet d’appeler l’accesseur set uniquement à partir des constructeurs du type. C’est plus restrictif que l’accesseur init sur l’accesseur set.

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 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.

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 pour une propriété partial ne peut pas être une propriété auto-implémentée. Une propriété auto-implémentée utilise la même syntaxe qu’une déclaration de propriété partielle déclarée.

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 pas de 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 ou init assignée par l'accesseur.
  • Les propriétés peuvent être en lecture-écriture (elles ont un accesseur get et un accesseur set), en lecture seule (elles ont un accesseur get, mais pas d’accesseur set) ou en écriture seule (elles ont un accesseur set, mais pas d’accesseur get). 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.

Voir aussi