EnregistrementsRecords

Cette proposition effectue le suivi de la spécification de la fonctionnalité d’enregistrements C# 9, comme convenu par l’équipe de conception du langage C#.This proposal tracks the specification for the C# 9 records feature, as agreed to by the C# language design team.

La syntaxe d’un enregistrement est la suivante :The syntax for a record is as follows:

record_declaration
    : attributes? class_modifier* 'partial'? 'record' identifier type_parameter_list?
      parameter_list? record_base? type_parameter_constraints_clause* record_body
    ;

record_base
    : ':' class_type argument_list?
    | ':' interface_type_list
    | ':' class_type argument_list? ',' interface_type_list
    ;

record_body
    : '{' class_member_declaration* '}' ';'?
    | ';'
    ;

Les types d’enregistrements sont des types référence, similaires à une déclaration de classe.Record types are reference types, similar to a class declaration. Si un enregistrement record_base argument_list record_declaration ne contient pas de, il s’agit d’une erreur parameter_list .It is an error for a record to provide a record_base argument_list if the record_declaration does not contain a parameter_list. Au plus une déclaration de type partiel d’un enregistrement partiel peut fournir un parameter_list .At most one partial type declaration of a partial record may provide a parameter_list.

Les paramètres d’enregistrement ne peuvent pas utiliser ref out this les modificateurs, ou (mais in params sont autorisés).Record parameters cannot use ref, out or this modifiers (but in and params are allowed).

HéritageInheritance

Les enregistrements ne peuvent pas hériter de classes, sauf si la classe est object , et les classes ne peuvent pas hériter d’enregistrements.Records cannot inherit from classes, unless the class is object, and classes cannot inherit from records. Les enregistrements peuvent hériter d’autres enregistrements.Records can inherit from other records.

Membres d’un type d’enregistrementMembers of a record type

En plus des membres déclarés dans le corps d’enregistrement, un type d’enregistrement a des membres synthétisés supplémentaires.In addition to the members declared in the record body, a record type has additional synthesized members. Les membres sont synthétisés, sauf si un membre avec une signature « correspondante » est déclaré dans le corps de l’enregistrement ou si un membre non virtuel concret accessible avec une signature « correspondante » est hérité.Members are synthesized unless a member with a "matching" signature is declared in the record body or an accessible concrete non-virtual member with a "matching" signature is inherited. Deux membres sont considérés comme correspondants s’ils ont la même signature ou sont considérés comme « masqués » dans un scénario d’héritage.Two members are considered matching if they have the same signature or would be considered "hiding" in an inheritance scenario. Le fait qu’un membre d’un enregistrement soit nommé « clone » est une erreur.It is an error for a member of a record to be named "Clone". Il s’agit d’une erreur pour un champ d’instance d’un enregistrement dont le type n’est pas sécurisé.It is an error for an instance field of a record to have an unsafe type.

Les membres synthétisés sont les suivants :The synthesized members are as follows:

Membres d’égalitéEquality members

Si l’enregistrement est dérivé de object , le type d’enregistrement comprend une propriété en lecture seule synthétisée équivalant à une propriété déclarée comme suit :If the record is derived from object, the record type includes a synthesized readonly property equivalent to a property declared as follows:

Type EqualityContract { get; };

La propriété est private si le type d’enregistrement est sealed .The property is private if the record type is sealed. Sinon, la propriété est virtual et protected .Otherwise, the property is virtual and protected. La propriété peut être déclarée explicitement.The property can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne correspond pas à la signature ou l’accessibilité attendue, ou si la déclaration explicite ne permet pas de la substituer dans un type dérivé et que le type d’enregistrement n’est pas sealed .It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not sealed.

Si le type d’enregistrement est dérivé d’un type d’enregistrement de base Base , le type d’enregistrement comprend une propriété ReadOnly synthétisée équivalant à une propriété déclarée comme suit :If the record type is derived from a base record type Base, the record type includes a synthesized readonly property equivalent to a property declared as follows:

protected override Type EqualityContract { get; };

La propriété peut être déclarée explicitement.The property can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne correspond pas à la signature ou l’accessibilité attendue, ou si la déclaration explicite ne permet pas de la substituer dans un type dérivé et que le type d’enregistrement n’est pas sealed .It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not sealed. Il s’agit d’une erreur si une propriété synthétisée ou explicitement déclarée ne remplace pas une propriété avec cette signature dans le type d’enregistrement Base (par exemple, si la propriété est manquante dans Base , ou sealed, ou non virtuelle, etc.).It is an error if either synthesized, or explicitly declared property doesn't override a property with this signature in the record type Base (for example, if the property is missing in the Base, or sealed, or not virtual, etc.). La propriété synthétisée retourne typeof(R)R est le type d’enregistrement.The synthesized property returns typeof(R) where R is the record type.

Le type d’enregistrement implémente System.IEquatable<R> et comprend une surcharge fortement typée synthétisée de Equals(R? other)R est le type d’enregistrement.The record type implements System.IEquatable<R> and includes a synthesized strongly-typed overload of Equals(R? other) where R is the record type. La méthode est public , et la méthode est, virtual sauf si le type d’enregistrement est sealed .The method is public, and the method is virtual unless the record type is sealed. La méthode peut être déclarée explicitement.The method can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne correspond pas à la signature ou à l’accessibilité attendue, ou que la déclaration explicite ne permet pas de la substituer dans un type dérivé et que le type d’enregistrement n’est pas sealed .It is an error if the explicit declaration does not match the expected signature or accessibility, or the explicit declaration doesn't allow overriding it in a derived type and the record type is not sealed.

Si Equals(R? other) est défini par l’utilisateur (non synthétisé) mais qu’il ne l’est GetHashCode pas, un avertissement est généré.If Equals(R? other) is user-defined (not synthesized) but GetHashCode is not, a warning is produced.

public virtual bool Equals(R? other);

La synthèse Equals(R?) retourne true si et seulement si chacun des éléments suivants est true :The synthesized Equals(R?) returns true if and only if each of the following are true:

  • other n’est pas null , etother is not null, and
  • Pour chaque champ d’instance fieldN dans le type d’enregistrement qui n’est pas hérité, la valeur de System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)TN est le type de champ, etFor each instance field fieldN in the record type that is not inherited, the value of System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN) where TN is the field type, and
  • S’il existe un type d’enregistrement de base, la valeur de base.Equals(other) (un appel non virtuel à public virtual bool Equals(Base? other) ); sinon, la valeur de EqualityContract == other.EqualityContract .If there is a base record type, the value of base.Equals(other) (a non-virtual call to public virtual bool Equals(Base? other)); otherwise the value of EqualityContract == other.EqualityContract.

Le type d’enregistrement comprend == des opérateurs synthétisés et != équivalents aux opérateurs déclarés comme suit :The record type includes synthesized == and != operators equivalent to operators declared as follows:

public static bool operator==(R? left, R? right)
    => (object)left == right || (left?.Equals(right) ?? false);
public static bool operator!=(R? left, R? right)
    => !(left == right);

La Equals méthode appelée par l' == opérateur est la Equals(R? other) méthode spécifiée ci-dessus.The Equals method called by the == operator is the Equals(R? other) method specified above. L' != opérateur délègue à l' == opérateur.The != operator delegates to the == operator. Il s’agit d’une erreur si les opérateurs sont déclarés explicitement.It is an error if the operators are declared explicitly.

Si le type d’enregistrement est dérivé d’un type d’enregistrement de base Base , le type d’enregistrement comprend un remplacement synthétisé équivalent à une méthode déclarée comme suit :If the record type is derived from a base record type Base, the record type includes a synthesized override equivalent to a method declared as follows:

public sealed override bool Equals(Base? other);

Il s’agit d’une erreur si la substitution est déclarée explicitement.It is an error if the override is declared explicitly. Il s’agit d’une erreur si la méthode ne remplace pas une méthode avec la même signature dans le type d’enregistrement Base (par exemple, si la méthode est manquante dans Base , ou sealed, ou non virtuelle, etc.).It is an error if the method doesn't override a method with same signature in record type Base (for example, if the method is missing in the Base, or sealed, or not virtual, etc.). La valeur de substitution synthétisée est retournée Equals((object?)other) .The synthesized override returns Equals((object?)other).

Le type d’enregistrement comprend un remplacement synthétisé équivalent à une méthode déclarée comme suit :The record type includes a synthesized override equivalent to a method declared as follows:

public override bool Equals(object? obj);

Il s’agit d’une erreur si la substitution est déclarée explicitement.It is an error if the override is declared explicitly. Il s’agit d’une erreur si la méthode n’est pas substituée object.Equals(object? obj) (par exemple, en raison de l’occultation dans les types de base intermédiaires, etc.).It is an error if the method doesn't override object.Equals(object? obj) (for example, due to shadowing in intermediate base types, etc.). La valeur de remplacement synthétisé retourne Equals(other as R)R est le type d’enregistrement.The synthesized override returns Equals(other as R) where R is the record type.

Le type d’enregistrement comprend un remplacement synthétisé équivalent à une méthode déclarée comme suit :The record type includes a synthesized override equivalent to a method declared as follows:

public override int GetHashCode();

La méthode peut être déclarée explicitement.The method can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne permet pas de la remplacer dans un type dérivé et que le type d’enregistrement n’est pas sealed .It is an error if the explicit declaration doesn't allow overriding it in a derived type and the record type is not sealed. Il s’agit d’une erreur si une méthode synthétisée ou explicitement déclarée ne se substitue pas object.GetHashCode() (par exemple, en raison de l’occultation dans les types de base intermédiaires, etc.).It is an error if either synthesized, or explicitly declared method doesn't override object.GetHashCode() (for example, due to shadowing in intermediate base types, etc.).

Un avertissement est signalé si l’un des Equals(R?) et GetHashCode() est explicitement déclaré, mais que l’autre méthode n’est pas explicite.A warning is reported if one of Equals(R?) and GetHashCode() is explicitly declared but the other method is not explicit.

La substitution synthétisée de GetHashCode() retourne un int résultat de la combinaison des valeurs suivantes :The synthesized override of GetHashCode() returns an int result of combining the following values:

  • Pour chaque champ d’instance fieldN dans le type d’enregistrement qui n’est pas hérité, la valeur de System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)TN est le type de champ, etFor each instance field fieldN in the record type that is not inherited, the value of System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN) where TN is the field type, and
  • S’il existe un type d’enregistrement de base, la valeur de base.GetHashCode() ; sinon, la valeur de System.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract) .If there is a base record type, the value of base.GetHashCode(); otherwise the value of System.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract).

Par exemple, considérez les types d’enregistrements suivants :For example, consider the following record types:

record R1(T1 P1);
record R2(T1 P1, T2 P2) : R1(P1);
record R3(T1 P1, T2 P2, T3 P3) : R2(P1, P2);

Pour ces types d’enregistrements, les membres de l’égalité synthétisée ressemblent à ceci :For those record types, the synthesized equality members would be something like:

class R1 : IEquatable<R1>
{
    public T1 P1 { get; init; }
    protected virtual Type EqualityContract => typeof(R1);
    public override bool Equals(object? obj) => Equals(obj as R1);
    public virtual bool Equals(R1? other)
    {
        return !(other is null) &&
            EqualityContract == other.EqualityContract &&
            EqualityComparer<T1>.Default.Equals(P1, other.P1);
    }
    public static bool operator==(R1? left, R1? right)
        => (object)left == right || (left?.Equals(right) ?? false);
    public static bool operator!=(R1? left, R1? right)
        => !(left == right);
    public override int GetHashCode()
    {
        return Combine(EqualityComparer<Type>.Default.GetHashCode(EqualityContract),
            EqualityComparer<T1>.Default.GetHashCode(P1));
    }
}

class R2 : R1, IEquatable<R2>
{
    public T2 P2 { get; init; }
    protected override Type EqualityContract => typeof(R2);
    public override bool Equals(object? obj) => Equals(obj as R2);
    public sealed override bool Equals(R1? other) => Equals((object?)other);
    public virtual bool Equals(R2? other)
    {
        return base.Equals((R1?)other) &&
            EqualityComparer<T2>.Default.Equals(P2, other.P2);
    }
    public static bool operator==(R2? left, R2? right)
        => (object)left == right || (left?.Equals(right) ?? false);
    public static bool operator!=(R2? left, R2? right)
        => !(left == right);
    public override int GetHashCode()
    {
        return Combine(base.GetHashCode(),
            EqualityComparer<T2>.Default.GetHashCode(P2));
    }
}

class R3 : R2, IEquatable<R3>
{
    public T3 P3 { get; init; }
    protected override Type EqualityContract => typeof(R3);
    public override bool Equals(object? obj) => Equals(obj as R3);
    public sealed override bool Equals(R2? other) => Equals((object?)other);
    public virtual bool Equals(R3? other)
    {
        return base.Equals((R2?)other) &&
            EqualityComparer<T3>.Default.Equals(P3, other.P3);
    }
    public static bool operator==(R3? left, R3? right)
        => (object)left == right || (left?.Equals(right) ?? false);
    public static bool operator!=(R3? left, R3? right)
        => !(left == right);
    public override int GetHashCode()
    {
        return Combine(base.GetHashCode(),
            EqualityComparer<T3>.Default.GetHashCode(P3));
    }
}

Copier et cloner des membresCopy and Clone members

Un type d’enregistrement contient deux membres de copie :A record type contains two copying members:

  • Constructeur acceptant un seul argument du type d’enregistrement.A constructor taking a single argument of the record type. Il est appelé « constructeur de copie ».It is referred to as a "copy constructor".
  • Méthode « Clone » d’instance sans paramètre publique synthétisée avec un nom réservé par le compilateurA synthesized public parameterless instance "clone" method with a compiler-reserved name

L’objectif du constructeur de copie est de copier l’état du paramètre vers la nouvelle instance en cours de création.The purpose of the copy constructor is to copy the state from the parameter to the new instance being created. Ce constructeur n’exécute aucun initialiseur de champ/propriété d’instance présent dans la déclaration d’enregistrement.This constructor doesn't run any instance field/property initializers present in the record declaration. Si le constructeur n’est pas explicitement déclaré, un constructeur est synthétisé par le compilateur.If the constructor is not explicitly declared, a constructor will be synthesized by the compiler. Si l’enregistrement est sealed, le constructeur est privé, sinon il est protégé.If the record is sealed, the constructor will be private, otherwise it will be protected. Un constructeur de copie explicitement déclaré doit être public ou protected, sauf si l’enregistrement est sealed.An explicitly declared copy constructor must be either public or protected, unless the record is sealed. La première chose que le constructeur doit faire, est d’appeler un constructeur de copie de la base, ou un constructeur d’objet sans paramètre si l’enregistrement hérite de l’objet.The first thing the constructor must do, is to call a copy constructor of the base, or a parameter-less object constructor if the record inherits from object. Une erreur est signalée si un constructeur de copie défini par l’utilisateur utilise un initialiseur de constructeur implicite ou explicite qui ne respecte pas cette exigence.An error is reported if a user-defined copy constructor uses an implicit or explicit constructor initializer that doesn't fulfill this requirement. Après l’appel d’un constructeur de copie de base, un constructeur de copie synthétisé copie les valeurs de tous les champs d’instance implicitement ou explicitement déclarés dans le type d’enregistrement.After a base copy constructor is invoked, a synthesized copy constructor copies values for all instance fields implicitly or explicitly declared within the record type. La seule présence d’un constructeur de copie, qu’il soit explicite ou Implicit, n’empêche pas l’ajout automatique d’un constructeur d’instance par défaut.The sole presence of a copy constructor, whether explicit or implicit, doesn't prevent an automatic addition of a default instance constructor.

Si une méthode « Clone » virtuelle est présente dans l’enregistrement de base, la méthode « Clone » synthétisée la remplace et le type de retour de la méthode est le type conteneur actuel si la fonctionnalité « covariant retourne » est prise en charge et le type de retour de substitution dans le cas contraire.If a virtual "clone" method is present in the base record, the synthesized "clone" method overrides it and the return type of the method is the current containing type if the "covariant returns" feature is supported and the override return type otherwise. Une erreur est générée si la méthode Clone de l’enregistrement de base est sealed.An error is produced if the base record clone method is sealed. Si une méthode « Clone » virtuelle n’est pas présente dans l’enregistrement de base, le type de retour de la méthode Clone est le type conteneur et la méthode est virtuelle, sauf si l’enregistrement est sealed ou abstract.If a virtual "clone" method is not present in the base record, the return type of the clone method is the containing type and the method is virtual, unless the record is sealed or abstract. Si l’enregistrement conteneur est abstrait, la méthode de clonage synthétisé est également abstraite.If the containing record is abstract, the synthesized clone method is also abstract. Si la méthode « Clone » n’est pas abstraite, elle retourne le résultat d’un appel à un constructeur de copie.If the "clone" method is not abstract, it returns the result of a call to a copy constructor.

Impression des membres : méthodes PrintMembers et ToStringPrinting members: PrintMembers and ToString methods

Si l’enregistrement est dérivé de object , l’enregistrement contient une méthode synthétisée équivalente à une méthode déclarée comme suit :If the record is derived from object, the record includes a synthesized method equivalent to a method declared as follows:

bool PrintMembers(System.Text.StringBuilder builder);

La méthode est private si le type d’enregistrement est sealed .The method is private if the record type is sealed. Sinon, la méthode est virtual et protected .Otherwise, the method is virtual and protected.

La méthode :The method:

  1. pour chacun des membres imprimables de l’enregistrement (champ public non statique et membres de propriété lisibles), ajoute le nom de ce membre suivi de « = » suivi de la valeur du membre, séparée par « , ».for each of the record's printable members (non-static public field and readable property members), appends that member's name followed by " = " followed by the member's value separated with ", ",
  2. retourne la valeur true si l’enregistrement contient des membres imprimables.return true if the record has printable members.

Pour un membre qui a un type valeur, nous allons convertir sa valeur en représentation sous forme de chaîne à l’aide de la méthode la plus efficace disponible pour la plateforme cible.For a member that has a value type, we will convert its value to a string representation using the most efficient method available to the target platform. À l’heure actuelle, cela signifie appeler ToString avant de passer à StringBuilder.Append .At present that means calling ToString before passing to StringBuilder.Append.

Si le type d’enregistrement est dérivé d’un enregistrement de base Base , l’enregistrement contient un remplacement synthétisé équivalent à une méthode déclarée comme suit :If the record type is derived from a base record Base, the record includes a synthesized override equivalent to a method declared as follows:

protected override bool PrintMembers(StringBuilder builder);

Si l’enregistrement n’a pas de membre imprimable, la méthode appelle la PrintMembers méthode de base à l’aide d’un argument (son builder paramètre) et retourne le résultat.If the record has no printable members, the method calls the base PrintMembers method with one argument (its builder parameter) and returns the result.

Sinon, la méthode :Otherwise, the method:

  1. appelle la PrintMembers méthode de base avec un argument (son builder paramètre).calls the base PrintMembers method with one argument (its builder parameter),
  2. Si la PrintMembers méthode a retourné la valeur true, ajoutez « , » au générateur,if the PrintMembers method returned true, append ", " to the builder,
  3. pour chacun des membres imprimables de l’enregistrement, ajoute le nom de ce membre suivi de « = » suivi de la valeur du membre : this.member (ou this.member.ToString() pour les types valeur), séparée par « , »,for each of the record's printable members, appends that member's name followed by " = " followed by the member's value: this.member (or this.member.ToString() for value types), separated with ", ",
  4. retourne la valeur true.return true.

La PrintMembers méthode peut être déclarée explicitement.The PrintMembers method can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne correspond pas à la signature ou l’accessibilité attendue, ou si la déclaration explicite ne permet pas de la substituer dans un type dérivé et que le type d’enregistrement n’est pas sealed .It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not sealed.

L’enregistrement contient une méthode synthétisée équivalente à une méthode déclarée comme suit :The record includes a synthesized method equivalent to a method declared as follows:

public override string ToString();

La méthode peut être déclarée explicitement.The method can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne correspond pas à la signature ou l’accessibilité attendue, ou si la déclaration explicite ne permet pas de la substituer dans un type dérivé et que le type d’enregistrement n’est pas sealed .It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not sealed. Il s’agit d’une erreur si une méthode synthétisée ou explicitement déclarée ne se substitue pas object.ToString() (par exemple, en raison de l’occultation dans les types de base intermédiaires, etc.).It is an error if either synthesized, or explicitly declared method doesn't override object.ToString() (for example, due to shadowing in intermediate base types, etc.).

La méthode synthétisée :The synthesized method:

  1. crée une StringBuilder instance,creates a StringBuilder instance,
  2. Ajoute le nom d’enregistrement au générateur, suivi de « { »,appends the record name to the builder, followed by " { ",
  3. appelle la méthode de l’enregistrement PrintMembers en lui donnant le générateur, suivi de «» si elle a retourné la valeur true,invokes the record's PrintMembers method giving it the builder, followed by " " if it returned true,
  4. Ajoute « } »,appends "}",
  5. retourne le contenu du générateur avec builder.ToString() .returns the builder's contents with builder.ToString().

Par exemple, considérez les types d’enregistrements suivants :For example, consider the following record types:

record R1(T1 P1);
record R2(T1 P1, T2 P2, T3 P3) : R1(P1);

Pour ces types d’enregistrements, les membres de l’impression synthétisée ressemblent à ceci :For those record types, the synthesized printing members would be something like:

class R1 : IEquatable<R1>
{
    public T1 P1 { get; init; }
    
    protected virtual bool PrintMembers(StringBuilder builder)
    {
        builder.Append(nameof(P1));
        builder.Append(" = ");
        builder.Append(this.P1); // or builder.Append(this.P1.ToString()); if P1 has a value type
        
        return true;
    }
    
    public override string ToString()
    {
        var builder = new StringBuilder();
        builder.Append(nameof(R1));
        builder.Append(" { ");

        if (PrintMembers(builder))
            builder.Append(" ");

        builder.Append("}");
        return builder.ToString();
    }
}

class R2 : R1, IEquatable<R2>
{
    public T2 P2 { get; init; }
    public T3 P3 { get; init; }
    
    protected override bool PrintMembers(StringBuilder builder)
    {
        if (base.PrintMembers(builder))
            builder.Append(", ");
            
        builder.Append(nameof(P2));
        builder.Append(" = ");
        builder.Append(this.P2); // or builder.Append(this.P2); if P2 has a value type
        
        builder.Append(", ");
        
        builder.Append(nameof(P3));
        builder.Append(" = ");
        builder.Append(this.P3); // or builder.Append(this.P3); if P3 has a value type
        
        return true;
    }
    
    public override string ToString()
    {
        var builder = new StringBuilder();
        builder.Append(nameof(R2));
        builder.Append(" { ");

        if (PrintMembers(builder))
            builder.Append(" ");

        builder.Append("}");
        return builder.ToString();
    }
}

Membres d’enregistrement positionnelPositional record members

Outre les membres ci-dessus, les enregistrements avec une liste de paramètres (« enregistrements positionnels ») synthétisent les membres supplémentaires avec les mêmes conditions que les membres ci-dessus.In addition to the above members, records with a parameter list ("positional records") synthesize additional members with the same conditions as the members above.

Constructeur principalPrimary Constructor

Un type d’enregistrement a un constructeur public dont la signature correspond aux paramètres de valeur de la déclaration de type.A record type has a public constructor whose signature corresponds to the value parameters of the type declaration. C’est ce que l’on appelle le constructeur principal pour le type, et le constructeur de classe par défaut déclaré implicitement, s’il est présent, doit être supprimé.This is called the primary constructor for the type, and causes the implicitly declared default class constructor, if present, to be suppressed. C’est une erreur d’avoir un constructeur principal et un constructeur avec la même signature déjà présente dans la classe.It is an error to have a primary constructor and a constructor with the same signature already present in the class.

Au moment de l’exécution, le constructeur principalAt runtime the primary constructor

  1. exécute les initialiseurs d’instance qui apparaissent dans le corps de classeexecutes the instance initializers appearing in the class-body

  2. appelle le constructeur de classe de base avec les arguments fournis dans la record_base clause, le cas échéant.invokes the base class constructor with the arguments provided in the record_base clause, if present

Si un enregistrement a un constructeur principal, tout constructeur défini par l’utilisateur, à l’exception de « constructeur de copie », doit avoir un this initialiseur de constructeur explicite.If a record has a primary constructor, any user-defined constructor, except "copy constructor" must have an explicit this constructor initializer.

Les paramètres du constructeur principal ainsi que les membres de l’enregistrement se trouvent dans la portée au sein argument_list de la record_base clause et dans les initialiseurs de champs d’instance ou de propriétés.Parameters of the primary constructor as well as members of the record are in scope within the argument_list of the record_base clause and within initializers of instance fields or properties. Les membres d’instance seraient une erreur à ces emplacements (à l’instar de la façon dont les membres d’instance sont dans la portée dans les initialiseurs de constructeur standard aujourd’hui, mais une erreur à utiliser), mais les paramètres du constructeur principal seraient dans la portée et utilisables et créeraient un cliché instantané des membres.Instance members would be an error in these locations (similar to how instance members are in scope in regular constructor initializers today, but an error to use), but the parameters of the primary constructor would be in scope and useable and would shadow members. Les membres statiques seraient également utilisables, de la même façon que les appels de base et les initialiseurs fonctionnent aujourd’hui dans les constructeurs ordinaires.Static members would also be useable, similar to how base calls and initializers work in ordinary constructors today.

Un avertissement est généré si un paramètre du constructeur principal n’est pas lu.A warning is produced if a parameter of the primary constructor is not read.

Les variables d’expression déclarées dans le argument_list sont dans la portée dans le argument_list .Expression variables declared in the argument_list are in scope within the argument_list. Les mêmes règles d’occultation qu’au sein d’une liste d’arguments d’un initialiseur de constructeur normal s’appliquent.The same shadowing rules as within an argument list of a regular constructor initializer apply.

PropriétésProperties

Pour chaque paramètre d’enregistrement d’une déclaration de type d’enregistrement, il existe un membre de propriété public correspondant dont le nom et le type sont extraits de la déclaration de paramètre de valeur.For each record parameter of a record type declaration there is a corresponding public property member whose name and type are taken from the value parameter declaration.

Pour un enregistrement :For a record:

  • Une get propriété publique et une init propriété automatique sont créées (voir init spécification d’accesseur distincte).A public get and init auto-property is created (see separate init accessor specification). Une propriété héritée abstract avec le type correspondant est substituée.An inherited abstract property with matching type is overridden. Il s’agit d’une erreur si la propriété héritée n’a pas public get de init accesseurs substituables.It is an error if the inherited property does not have public overridable get and init accessors. Il s’agit d’une erreur si la propriété héritée est masquée.It is an error if the inherited property is hidden.
    La propriété automatique est initialisée à la valeur du paramètre de constructeur principal correspondant.The auto-property is initialized to the value of the corresponding primary constructor parameter. Les attributs peuvent être appliqués à la propriété automatique synthétisée et à son champ de stockage à l’aide property: field: de cibles ou pour les attributs qui sont appliqués de façon syntaxique au paramètre d’enregistrement correspondant.Attributes can be applied to the synthesized auto-property and its backing field by using property: or field: targets for attributes syntactically applied to the corresponding record parameter.

DéconstruireDeconstruct

Un enregistrement positionnel avec au moins un paramètre synthétise une méthode d’instance publique qui retourne une void appelée Deconstruct avec une déclaration de paramètre out pour chaque paramètre de la déclaration du constructeur principal.A positional record with at least one parameter synthesizes a public void-returning instance method called Deconstruct with an out parameter declaration for each parameter of the primary constructor declaration. Chaque paramètre de la méthode Deconstruct a le même type que le paramètre correspondant de la déclaration du constructeur principal.Each parameter of the Deconstruct method has the same type as the corresponding parameter of the primary constructor declaration. Le corps de la méthode assigne à la valeur d’un membre d’instance un accès à un membre du même nom.The body of the method assigns each parameter of the Deconstruct method to the value from an instance member access to a member of the same name. La méthode peut être déclarée explicitement.The method can be declared explicitly. Il s’agit d’une erreur si la déclaration explicite ne correspond pas à la signature ou à l’accessibilité attendue, ou qu’elle est statique.It is an error if the explicit declaration does not match the expected signature or accessibility, or is static.

Expression withwith expression

Une with expression est une nouvelle expression utilisant la syntaxe suivante.A with expression is a new expression using the following syntax.

with_expression
    : switch_expression
    | switch_expression 'with' '{' member_initializer_list? '}'
    ;

member_initializer_list
    : member_initializer (',' member_initializer)*
    ;

member_initializer
    : identifier '=' expression
    ;

Une with expression n’est pas autorisée en tant qu’instruction.A with expression is not permitted as a statement.

Une with expression permet une « mutation non destructrice », conçue pour produire une copie de l’expression du récepteur avec les modifications des assignations dans le member_initializer_list .A with expression allows for "non-destructive mutation", designed to produce a copy of the receiver expression with modifications in assignments in the member_initializer_list.

Une with expression valide a un récepteur avec un type non void.A valid with expression has a receiver with a non-void type. Le type de récepteur doit être un enregistrement.The receiver type must be a record.

Sur le côté droit de l' with expression se trouve un member_initializer_list avec une séquence d’assignations à identifier, qui doit être un champ ou une propriété d’instance accessible du type du récepteur.On the right hand side of the with expression is a member_initializer_list with a sequence of assignments to identifier, which must be an accessible instance field or property of the receiver's type.

Tout d’abord, la méthode « Clone » du récepteur (spécifiée ci-dessus) est appelée et son résultat est converti en type du récepteur.First, receiver's "clone" method (specified above) is invoked and its result is converted to the receiver's type. Ensuite, chaque member_initializer est traité de la même façon qu’une assignation à un champ ou un accès à une propriété du résultat de la conversion.Then, each member_initializer is processed the same way as an assignment to a field or property access of the result of the conversion. Les affectations sont traitées dans l’ordre lexical.Assignments are processed in lexical order.