Partager via


Enregistrements (référence C#)

Vous utilisez le modificateur record pour définir un type de référence qui fournit des fonctionnalités intégrées pour encapsuler des données. C# 10 permet la syntaxe record class en tant que synonyme, afin de clarifier un type référence et record struct de définir un type valeur avec des fonctionnalités similaires.

Lorsque vous déclarez un constructeur principal sur un enregistrement, le compilateur génère des propriétés publiques pour les paramètres du constructeur principal. Les paramètres du constructeur principal d’un enregistrement sont appelés paramètres positionnels. Le compilateur crée des propriétés positionnelles qui reflètent le constructeur principal ou les paramètres positionnels. Le compilateur ne synthétise pas les propriétés des paramètres de constructeur principal sur les types qui n’ont pas le modificateur record.

Les deux exemples suivants illustrent les types référence record (ou record class) :

public record Person(string FirstName, string LastName);
public record Person
{
    public required string FirstName { get; init; }
    public required string LastName { get; init; }
};

Les deux exemples suivants illustrent record struct types valeur :

public readonly record struct Point(double X, double Y, double Z);
public record struct Point
{
    public double X { get; init; }
    public double Y { get; init; }
    public double Z { get; init; }
}

Vous pouvez également créer des enregistrements avec des propriétés et des champs mutables :

public record Person
{
    public required string FirstName { get; set; }
    public required string LastName { get; set; }
};

Les structs d’enregistrement peuvent également être mutables, les structs d’enregistrement positionnel, comme les structs d’enregistrement sans paramètres positionnels :

public record struct DataMeasurement(DateTime TakenAt, double Measurement);
public record struct Point
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
}

Bien que les enregistrements puissent être mutables, ils sont principalement destinés à prendre en charge les modèles de données immuables. Le type d’enregistrement procure les fonctionnalités suivantes :

Les exemples précédents montrent certaines distinctions entre les enregistrements qui sont des types référence et les enregistrements qui sont des types valeur :

  • Un record ou un record class déclare un type référence. Le mot clé class est facultatif, mais peut apporter de la clarté aux lecteurs. Un record struct déclare une classe de valeur.
  • Les propriétés positionnelles sont immuables dans un record class et un readonly record struct. Elles sont mutables dans un record struct.

Le reste de cet article traite des types record class et record struct. Les différences sont détaillées dans chaque section. Vous devez choisir entre un record class et un record struct, ce qui est similaire à un choix entre un class et un struct. Le terme enregistrement est utilisé pour décrire le comportement qui s’applique à tous les types d’enregistrements. record struct ou record class est utilisé pour décrire un comportement qui s’applique uniquement aux types de struct ou de classe, respectivement. Le type record struct a été introduit en C# 10.

Syntaxe positionnelle pour la définition de propriété

Vous pouvez utiliser des paramètres positionnels pour déclarer des propriétés d’un enregistrement et initialiser les valeurs de propriété lorsque vous créez une instance :

public record Person(string FirstName, string LastName);

public static void Main()
{
    Person person = new("Nancy", "Davolio");
    Console.WriteLine(person);
    // output: Person { FirstName = Nancy, LastName = Davolio }
}

Lorsque vous utilisez la syntaxe positionnelle pour la définition de propriété, le compilateur crée :

  • Une propriété publique implémentée automatiquement pour chaque paramètre positionnel fourni dans la déclaration d’enregistrement.
    • Pour les types record et les types readonly record struct : une propriété init uniquement .
    • Pour les types record struct : une propriété en lecture/écriture.
  • Un constructeur principal dont les paramètres correspondent aux paramètres positionnels de la déclaration d’enregistrement.
  • Pour les types de struct d’enregistrement, constructeur sans paramètre qui définit chaque champ à sa valeur par défaut.
  • Une méthode Deconstruct avec un paramètre out pour chaque paramètre positionnel fourni dans la déclaration d’enregistrement. La méthode déconstruit les propriétés définies à l’aide de la syntaxe positionnelle ; elle ignore les propriétés définies à l’aide de la syntaxe de propriété standard.

Vous pouvez ajouter des attributs à l’un de ces éléments créés par le compilateur à partir de la définition d’enregistrement. Vous pouvez ajouter une cible à n’importe quel attribut que vous appliquez aux propriétés de l’enregistrement positionnel. L’exemple suivant applique le System.Text.Json.Serialization.JsonPropertyNameAttribute à chaque propriété de l’enregistrement Person. La cible property: indique que l’attribut est appliqué à la propriété générée par le compilateur. D’autres valeurs sont field:, afin d’appliquer l’attribut au champ et param:, afin d’appliquer l’attribut au paramètre.

/// <summary>
/// Person record type
/// </summary>
/// <param name="FirstName">First Name</param>
/// <param name="LastName">Last Name</param>
/// <remarks>
/// The person type is a positional record containing the
/// properties for the first and last name. Those properties
/// map to the JSON elements "firstName" and "lastName" when
/// serialized or deserialized.
/// </remarks>
public record Person([property: JsonPropertyName("firstName")] string FirstName, 
    [property: JsonPropertyName("lastName")] string LastName);

L’exemple précédent montre également comment créer des commentaires de documentation XML pour l’enregistrement. Vous pouvez ajouter la balise <param> pour ajouter de la documentation pour les paramètres du constructeur principal.

Si la définition de propriété implémentée automatiquement n’est pas celle que vous souhaitez, vous pouvez définir votre propre propriété du même nom. Par exemple, vous pourriez souhaiter modifier l’accessibilité ou la mutabilité, ou fournir une implémentation pour l’accesseur get ou set. Si vous déclarez la propriété dans votre source, vous devez l’initialiser à partir du paramètre positionnel de l’enregistrement. Si votre propriété est implémentée automatiquement, vous devez initialiser la propriété. Si vous ajoutez un champ de stockage dans votre source, vous devez initialiser le champ de stockage. Le déconstructeur généré utilise votre définition de propriété. Par exemple, l’exemple suivant déclare les propriétés FirstName et LastName d’un enregistrement positionnel public, mais limite le paramètre positionnel Id à internal. Vous pouvez utiliser cette syntaxe pour les enregistrements et les types de struct d’enregistrement.

public record Person(string FirstName, string LastName, string Id)
{
    internal string Id { get; init; } = Id;
}

public static void Main()
{
    Person person = new("Nancy", "Davolio", "12345");
    Console.WriteLine(person.FirstName); //output: Nancy

}

Un type d’enregistrement n’a pas besoin de déclarer de propriétés positionnelles. Vous pouvez déclarer un enregistrement sans aucune propriété positionnelle, et vous pouvez déclarer d’autres champs et propriétés, comme dans l’exemple suivant :

public record Person(string FirstName, string LastName)
{
    public string[] PhoneNumbers { get; init; } = [];
};

Si vous définissez des propriétés à l’aide de la syntaxe de propriété standard, mais que vous omettez le modificateur d’accès, les propriétés sont implicitement private.

Immuabilité

Un enregistrement positionnel et un struct d’enregistrement positionnel en lecture seule déclarent des propriétés init uniquement. Un struct d’enregistrement positionnel déclare des propriétés en lecture-écriture. Vous pouvez remplacer l’une de ces valeurs par défaut, comme indiqué dans la section précédente.

L’immuabilité peut être utile si vous avez besoin d’un type centré sur les données pour être thread-safe ou si vous dépendez d’un code de hachage restant le même dans une table de hachage. Toutefois, l’immuabilité n’est pas appropriée pour tous les scénarios de données. Entity Framework Core, par exemple, ne prend pas en charge la mise à jour avec des types d’entités immuables.

Les propriétés init uniquement, qu’elles soient créées à partir de paramètres positionnels (record classet readonly record struct) ou en spécifiant init des accesseurs, ont une immuabilité superficielle. Après l’initialisation, vous ne pouvez pas modifier la valeur des propriétés de type valeur ou la référence des propriétés de type référence. Toutefois, les données auxquelles fait référence une propriété de type référence peuvent être modifiées. L’exemple suivant montre que le contenu d’une propriété immuable de type référence (un tableau dans ce cas) est mutable :

public record Person(string FirstName, string LastName, string[] PhoneNumbers);

public static void Main()
{
    Person person = new("Nancy", "Davolio", new string[1] { "555-1234" });
    Console.WriteLine(person.PhoneNumbers[0]); // output: 555-1234

    person.PhoneNumbers[0] = "555-6789";
    Console.WriteLine(person.PhoneNumbers[0]); // output: 555-6789
}

Les fonctionnalités propres aux types d’enregistrements sont implémentées par des méthodes synthétisées par le compilateur, et aucune de ces méthodes ne compromet l’immuabilité en modifiant l’état de l’objet. Sauf indication contraire, les méthodes synthétisées sont générées pour les déclarations record, record structet readonly record struct.

Égalité des valeurs

Si vous ne remplacez pas les méthodes d’égalité, le type que vous déclarez détermine la façon dont l’égalité est définie :

  • Pour les types class, deux objets sont égaux s’ils font référence au même objet en mémoire.
  • Pour les types struct, deux objets sont égaux s’ils sont du même type et stockent les mêmes valeurs.
  • Pour les types avec le modificateur record, (record class, record struct et readonly record struct), deux objets sont égaux s’ils sont du même type et stockent les mêmes valeurs.

La définition de l’égalité pour un record struct est la même que pour un struct. La différence est que pour un struct, l’implémentation se trouve dans ValueType.Equals(Object) et s’appuie sur la réflexion. Pour les enregistrements, l’implémentation est synthétisée par le compilateur et utilise les membres de données déclarés.

L’égalité des références est requise pour certains modèles de données. Par exemple, Entity Framework Core dépend de l’égalité des références pour s’assurer qu’il n’utilise qu’une seule instance d’un type d’entité pour ce qui est conceptuellement une seule entité. Pour cette raison, les enregistrements et les structs d’enregistrement ne sont pas appropriés pour une utilisation en tant que types d’entités dans Entity Framework Core.

L’exemple suivant illustre l’égalité de valeur des types d’enregistrements :

public record Person(string FirstName, string LastName, string[] PhoneNumbers);

public static void Main()
{
    var phoneNumbers = new string[2];
    Person person1 = new("Nancy", "Davolio", phoneNumbers);
    Person person2 = new("Nancy", "Davolio", phoneNumbers);
    Console.WriteLine(person1 == person2); // output: True

    person1.PhoneNumbers[0] = "555-1234";
    Console.WriteLine(person1 == person2); // output: True

    Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
}

Pour implémenter l’égalité des valeurs, le compilateur synthétise plusieurs méthodes, notamment :

  • Un remplacement de Object.Equals(Object). Il s’agit d’une erreur si le remplacement est déclaré explicitement.

    Cette méthode est utilisée comme base pour la Object.Equals(Object, Object) méthode statique lorsque les deux paramètres ne sont pas null.

  • virtual, ou sealed, Equals(R? other)R est le type d’enregistrement. Cette méthode implémente IEquatable<T>. Cette méthode peut être déclarée explicitement.

  • Si le type d’enregistrement est dérivé d’un type d’enregistrement de base Base, Equals(Base? other). Il s’agit d’une erreur si le remplacement est déclaré explicitement. Si vous fournissez votre propre implémentation de Equals(R? other), fournissez également une implémentation de GetHashCode.

  • Un remplacement de Object.GetHashCode(). Cette méthode peut être déclarée explicitement.

  • Remplace les opérateurs == et !=. Il s’agit d’une erreur si les opérateurs sont déclarés explicitement.

  • Si le type d’enregistrement est dérivé d’un type d’enregistrement de base protected override Type EqualityContract { get; };. Cette propriété peut être déclarée explicitement. Pour plus d’informations, consultez Égalité dans les hiérarchies d’héritage.

Si un type d’enregistrement a une méthode qui correspond à la signature d’une méthode synthétisée autorisée à être déclarée explicitement, le compilateur ne synthétise pas cette méthode.

Mutation non destructrice

Si vous devez copier une instance avec certaines modifications, vous pouvez utiliser une expression with pour obtenir une mutation non destructrice. Une expression with crée une nouvelle instance d’enregistrement qui est une copie d’une instance d’enregistrement existante, avec les propriétés et les champs spécifiés modifiés. Vous utilisez la syntaxe d’initialiseur d’objet pour spécifier les valeurs à modifier, comme indiqué dans l’exemple suivant :

public record Person(string FirstName, string LastName)
{
    public string[] PhoneNumbers { get; init; }
}

public static void Main()
{
    Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
    Console.WriteLine(person1);
    // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }

    Person person2 = person1 with { FirstName = "John" };
    Console.WriteLine(person2);
    // output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
    Console.WriteLine(person1 == person2); // output: False

    person2 = person1 with { PhoneNumbers = new string[1] };
    Console.WriteLine(person2);
    // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
    Console.WriteLine(person1 == person2); // output: False

    person2 = person1 with { };
    Console.WriteLine(person1 == person2); // output: True
}

L’expression with peut définir des propriétés positionnelles ou des propriétés créées à l’aide de la syntaxe de propriété standard. Les propriétés explicitement déclarées doivent avoir un accesseur init ou set pour être modifiées dans une expression with.

Le résultat d’une expression with est une copie superficielle, ce qui signifie que pour une propriété de référence, seule la référence à une instance est copiée. L’enregistrement d’origine et la copie se terminent par une référence à la même instance.

Pour implémenter cette fonctionnalité pour les types record class, le compilateur synthétise une méthode clone et un constructeur de copie. La méthode clone virtuelle retourne un nouvel enregistrement initialisé par le constructeur de copie. Lorsque vous utilisez une expression with, le compilateur crée du code qui appelle la méthode clone, puis définit les propriétés spécifiées dans l’expression with.

Si vous avez besoin d’un comportement de copie différent, vous pouvez écrire votre propre constructeur de copie dans un record class. Si vous effectuez cette opération, le compilateur n’en synthétisera pas une. Réalisez votre constructeur private si l’enregistrement est sealed, sinon réalisez-le pour qu’il soit protected. Le compilateur ne synthétise pas un constructeur de copie pour les types record struct. Vous pouvez en écrire un, mais le compilateur ne génère pas d’appels pour les expressions with. Les valeurs de record struct sont copiées lors de l’affectation.

Vous ne pouvez pas remplacer la méthode clone et vous ne pouvez pas créer un membre nommé Clone dans n’importe quel type d’enregistrement. Le nom réel de la méthode clone est généré par le compilateur.

Mise en forme intégrée pour l’affichage

Les types d’enregistrements ont une méthode ToString générée par le compilateur qui affiche les noms et les valeurs des propriétés publiques et des champs. La méthode ToString retourne une chaîne au format suivant :

<nom du type d’enregistrement> { <nom de la propriété > = <valeur>, <nom de la propriété > = <valeur>, ...}

La chaîne imprimée pour <value> est la chaîne retournée par le ToString() pour le type de la propriété. Dans l’exemple suivant, ChildNames est un System.Array, où ToString retourne System.String[] :

Person { FirstName = Nancy, LastName = Davolio, ChildNames = System.String[] }

Pour implémenter cette fonctionnalité, dans les types record class, le compilateur synthétise une méthode virtuelle PrintMembers et un remplacement ToString. Dans les types record struct, ce membre est private. Le remplacement ToString crée un objet StringBuilder avec le nom de type suivi d’un crochet ouvrant. Il appelle PrintMembers pour ajouter des noms de propriétés et des valeurs, puis ajoute le crochet fermant. L’exemple suivant montre un code similaire à ce que contient le remplacement synthétisé :

public override string ToString()
{
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.Append("Teacher"); // type name
    stringBuilder.Append(" { ");
    if (PrintMembers(stringBuilder))
    {
        stringBuilder.Append(" ");
    }
    stringBuilder.Append("}");
    return stringBuilder.ToString();
}

Vous pouvez fournir votre propre implémentation de PrintMembers ou le remplacement ToString. Des exemples sont fournis ultérieurement dans cet article, dans la section PrintMembersMise en forme des enregistrements dérivés. En C# 10 et dans les versions ultérieures, votre implémentation de ToString peut inclure le modificateur sealed, ce qui empêche le compilateur de synthétiser une implémentation ToString pour tous les enregistrements dérivés. Vous pouvez créer une représentation de chaîne cohérente dans une hiérarchie de types record. (Les enregistrements dérivés auront toujours une méthode PrintMembers générée pour toutes les propriétés dérivées.)

Héritage

Cette section s'applique uniquement aux types record class.

Un enregistrement peut hériter d’un autre enregistrement. Toutefois, un enregistrement ne peut pas hériter d’une classe et une classe ne peut pas hériter d’un enregistrement.

Paramètres positionnels dans les types d’enregistrements dérivés

L’enregistrement dérivé déclare les paramètres positionnels pour tous les paramètres du constructeur principal de l’enregistrement de base. L’enregistrement de base déclare et initialise ces propriétés. L’enregistrement dérivé ne les masque pas, mais crée et initialise uniquement des propriétés pour les paramètres qui ne sont pas déclarés dans son enregistrement de base.

L’exemple suivant illustre l’héritage avec la syntaxe de propriété positionnelle :

public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);
public static void Main()
{
    Person teacher = new Teacher("Nancy", "Davolio", 3);
    Console.WriteLine(teacher);
    // output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}

Égalité dans les hiérarchies d’héritage

Cette section s’applique aux types record class, mais pas aux types record struct. Pour que deux variables d’enregistrement soient égales, le type d’exécution doit être égal. Les types des variables contenantes peuvent être différents. La comparaison de l’égalité héritée est illustrée dans l’exemple de code suivant :

public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);
public static void Main()
{
    Person teacher = new Teacher("Nancy", "Davolio", 3);
    Person student = new Student("Nancy", "Davolio", 3);
    Console.WriteLine(teacher == student); // output: False

    Student student2 = new Student("Nancy", "Davolio", 3);
    Console.WriteLine(student2 == student); // output: True
}

Dans l’exemple, toutes les variables sont déclarées sous la forme Person, même lorsque l’instance est un type dérivé de Student ou Teacher. Les instances ont les mêmes propriétés et les mêmes valeurs de propriété. Mais student == teacher retourne False bien que les deux soient des variables types Person, et student == student2 retourne True bien que l’une soit une variable Person et l’autre soit une variable Student. Le test d’égalité dépend du type d’exécution de l’objet réel, et non du type déclaré de la variable.

Pour implémenter ce comportement, le compilateur synthétise une propriété EqualityContract qui retourne un objet Type qui correspond au type de l’enregistrement. Le EqualityContract permet aux méthodes d’égalité de comparer le type d’exécution des objets lorsque l’égalité est vérifiée. Si le type de base d’un enregistrement est object, cette propriété est virtual. Si le type de base est un autre type d’enregistrement, cette propriété est un remplacement. Si le type d’enregistrement est sealed, cette propriété est en fait sealed, car le type est sealed.

Lorsque le code compare deux instances d’un type dérivé, les méthodes d’égalité synthétisées vérifient l’égalité de tous les membres de données des types de base et dérivés. La méthode synthétisée GetHashCode utilise la méthode GetHashCode de tous les membres de données déclarés dans le type de base et le type d’enregistrement dérivé. Les membres de données d’un record incluent tous les champs déclarés et le champ de stockage synthétisé du compilateur pour toutes les propriétés implémentées automatiquement.

Expressions with dans les enregistrements dérivés

Le résultat d’une expression with a le même type d’exécution que l’opérande de l’expression. Toutes les propriétés du type d’exécution sont copiées, mais vous pouvez uniquement définir les propriétés du type au moment de la compilation, comme le montre l’exemple suivant :

public record Point(int X, int Y)
{
    public int Zbase { get; set; }
};
public record NamedPoint(string Name, int X, int Y) : Point(X, Y)
{
    public int Zderived { get; set; }
};

public static void Main()
{
    Point p1 = new NamedPoint("A", 1, 2) { Zbase = 3, Zderived = 4 };

    Point p2 = p1 with { X = 5, Y = 6, Zbase = 7 }; // Can't set Name or Zderived
    Console.WriteLine(p2 is NamedPoint);  // output: True
    Console.WriteLine(p2);
    // output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = A, Zderived = 4 }

    Point p3 = (NamedPoint)p1 with { Name = "B", X = 5, Y = 6, Zbase = 7, Zderived = 8 };
    Console.WriteLine(p3);
    // output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = B, Zderived = 8 }
}

Mise en forme PrintMembers dans les enregistrements dérivés

La méthode synthétisée PrintMembers d’un type d’enregistrement dérivé appelle l’implémentation de base. Il en résulte que toutes les propriétés publiques et les champs des types dérivés et de base sont inclus dans la sortie ToString, comme illustré dans l’exemple suivant :

public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);

public static void Main()
{
    Person teacher = new Teacher("Nancy", "Davolio", 3);
    Console.WriteLine(teacher);
    // output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}

Vous pouvez fournir votre propre implémentation de la méthode PrintMembers. Dans ce cas, utilisez la signature suivante :

  • Pour un enregistrement sealed qui dérive de object (ne déclare pas d’enregistrement de base) : private bool PrintMembers(StringBuilder builder) ;
  • Pour un enregistrement sealed qui dérive d’un autre enregistrement (notez que le type englobant est sealed, donc la méthode est effectivement sealed) : protected override bool PrintMembers(StringBuilder builder) ;
  • Pour un enregistrement qui n’est pas sealed et dérive de l’objet : protected virtual bool PrintMembers(StringBuilder builder);
  • Pour un enregistrement qui n’est pas sealed et qui dérive d’un autre enregistrement : protected override bool PrintMembers(StringBuilder builder);

Voici un exemple de code qui remplace les méthodes synthétisées PrintMembers, l’une pour un type d’enregistrement qui dérive d’un objet et l’autre pour un type d’enregistrement qui dérive d’un autre enregistrement :

public abstract record Person(string FirstName, string LastName, string[] PhoneNumbers)
{
    protected virtual bool PrintMembers(StringBuilder stringBuilder)
    {
        stringBuilder.Append($"FirstName = {FirstName}, LastName = {LastName}, ");
        stringBuilder.Append($"PhoneNumber1 = {PhoneNumbers[0]}, PhoneNumber2 = {PhoneNumbers[1]}");
        return true;
    }
}

public record Teacher(string FirstName, string LastName, string[] PhoneNumbers, int Grade)
    : Person(FirstName, LastName, PhoneNumbers)
{
    protected override bool PrintMembers(StringBuilder stringBuilder)
    {
        if (base.PrintMembers(stringBuilder))
        {
            stringBuilder.Append(", ");
        };
        stringBuilder.Append($"Grade = {Grade}");
        return true;
    }
};

public static void Main()
{
    Person teacher = new Teacher("Nancy", "Davolio", new string[2] { "555-1234", "555-6789" }, 3);
    Console.WriteLine(teacher);
    // output: Teacher { FirstName = Nancy, LastName = Davolio, PhoneNumber1 = 555-1234, PhoneNumber2 = 555-6789, Grade = 3 }
}

Notes

En C# 10 et versions ultérieures, le compilateur synthétise PrintMembers dans des enregistrements dérivés même lorsqu’un enregistrement de base a scellé la méthode ToString. Vous pouvez également créer votre propre implémentation de PrintMembers.

Comportement du déconstructeur dans les enregistrements dérivés

La méthode Deconstruct d’un enregistrement dérivé retourne les valeurs de toutes les propriétés positionnelles du type au moment de la compilation. Si le type de variable est un enregistrement de base, seules les propriétés de l’enregistrement de base sont déconstruites, sauf si l’objet est casté vers le type dérivé. L’exemple suivant illustre l’appel d’un déconstructeur sur un enregistrement dérivé.

public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);

public static void Main()
{
    Person teacher = new Teacher("Nancy", "Davolio", 3);
    var (firstName, lastName) = teacher; // Doesn't deconstruct Grade
    Console.WriteLine($"{firstName}, {lastName}");// output: Nancy, Davolio

    var (fName, lName, grade) = (Teacher)teacher;
    Console.WriteLine($"{fName}, {lName}, {grade}");// output: Nancy, Davolio, 3
}

Contraintes génériques

Le mot clé record est un modificateur pour un type class ou struct. L’ajout du modificateur record inclut le comportement décrit précédemment dans cet article. Il n’existe aucune contrainte générique qui nécessite qu’un type soit un enregistrement. Un record class répond à la contrainte class. Un record struct répond à la contrainte struct. Pour plus d’informations, consultez Contraintes sur les paramètres de type.

spécification du langage C#

Pour plus d’informations, consultez la section Classes de la Spécification du langage C#.

Pour plus d’informations sur ces fonctionnalités, consultez les notes de proposition des fonctionnalités suivantes :

Voir aussi