RegistrosRecords
Esta propuesta realiza un seguimiento de la especificación de la característica de registros de C# 9, según lo acordado por el equipo de diseño del lenguaje C#.This proposal tracks the specification for the C# 9 records feature, as agreed to by the C# language design team.
La sintaxis de un registro es la siguiente: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* '}' ';'?
| ';'
;
Los tipos de registro son tipos de referencia, similares a una declaración de clase.Record types are reference types, similar to a class declaration. Es un error que un registro proporcione si record_base argument_list no contiene record_declaration 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.
Como máximo, una declaración de tipo parcial de un registro parcial puede proporcionar un parameter_list .At most one partial type declaration of a partial record may provide a parameter_list.
Los parámetros de registro no pueden usar modificadores o ref out this (pero in se permiten y params ).Record parameters cannot use ref, out or this modifiers (but in and params are allowed).
HerenciaInheritance
Los registros no pueden heredar de clases, a menos que la clase sea object y las clases no puedan heredar de los registros.Records cannot inherit from classes, unless the class is object, and classes cannot inherit from records. Los registros pueden heredar de otros registros.Records can inherit from other records.
Miembros de un tipo de registroMembers of a record type
Además de los miembros declarados en el cuerpo del registro, un tipo de registro tiene miembros sintetizados adicionales.In addition to the members declared in the record body, a record type has additional synthesized members. Los miembros se sintetizan a menos que se declare un miembro con una firma "correspondiente" en el cuerpo del registro o que se herede un miembro concreto no virtual accesible con una firma "correspondiente".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. Dos miembros se consideran que coinciden si tienen la misma firma o se consideran "ocultos" en un escenario de herencia.Two members are considered matching if they have the same signature or would be considered "hiding" in an inheritance scenario. Es un error que un miembro de un registro se deba llamar "Clone".It is an error for a member of a record to be named "Clone". Es un error que un campo de instancia de un registro tenga un tipo no seguro.It is an error for an instance field of a record to have an unsafe type.
Los miembros sintetizados son los siguientes:The synthesized members are as follows:
Miembros de igualdadEquality members
Si el registro se deriva de , el tipo de registro incluye una propiedad de solo lectura sintetizada equivalente a una propiedad declarada object de la siguiente manera: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 propiedad es private si el tipo de registro es sealed .The property is private if the record type is sealed. De lo contrario, la propiedad es virtual y protected .Otherwise, the property is virtual and protected.
La propiedad se puede declarar explícitamente.The property can be declared explicitly. Es un error si la declaración explícita no coincide con la firma o accesibilidad esperada, o si la declaración explícita no permite reemplazarla en un tipo derivado y el tipo de registro no es 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 el tipo de registro se deriva de un tipo de registro base , el tipo de registro incluye una propiedad de solo lectura sintetizada equivalente a una propiedad declarada como Base sigue: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 propiedad se puede declarar explícitamente.The property can be declared explicitly. Es un error si la declaración explícita no coincide con la firma o accesibilidad esperada, o si la declaración explícita no permite reemplazarla en un tipo derivado y el tipo de registro no es 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. Es un error si la propiedad sintetizada o declarada explícitamente no invalida una propiedad con esta firma en el tipo de registro (por ejemplo, si falta la propiedad en , o Base Base sealed, o no virtual, 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 propiedad sintetizada devuelve typeof(R) donde es el tipo de R registro.The synthesized property returns typeof(R) where R is the record type.
El tipo de registro implementa e incluye una sobrecarga System.IEquatable<R> sintetizada fuertemente typed de Equals(R? other) donde es el tipo de R registro.The record type implements System.IEquatable<R> and includes a synthesized strongly-typed overload of Equals(R? other) where R is the record type.
El método es y el método es a public menos que el tipo de registro sea virtual sealed .The method is public, and the method is virtual unless the record type is sealed.
El método se puede declarar explícitamente.The method can be declared explicitly. Es un error si la declaración explícita no coincide con la firma o accesibilidad esperada, o la declaración explícita no permite reemplazarla en un tipo derivado y el tipo de registro no es 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á definido por el usuario (no sintetizado), pero no lo GetHashCode está, se genera una advertencia.If Equals(R? other) is user-defined (not synthesized) but GetHashCode is not, a warning is produced.
public virtual bool Equals(R? other);
El sintetizado Equals(R?) devuelve si y solo si cada uno de los siguientes son true true :The synthesized Equals(R?) returns true if and only if each of the following are true:
otherno esnull, yotheris notnull, and- Para cada campo de instancia del tipo de registro que no se hereda, el valor
fieldNde where es el tipo de campoSystem.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)TNyFor each instance fieldfieldNin the record type that is not inherited, the value ofSystem.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)whereTNis the field type, and - Si hay un tipo de registro base, el valor de (una llamada no virtual a ); de lo
base.Equals(other)public virtual bool Equals(Base? other)contrario, el valor deEqualityContract == other.EqualityContract.If there is a base record type, the value ofbase.Equals(other)(a non-virtual call topublic virtual bool Equals(Base? other)); otherwise the value ofEqualityContract == other.EqualityContract.
El tipo de registro incluye operadores == sintetizados != y equivalentes a los operadores declarados como sigue: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);
El Equals método al que llama el operador es el método especificado == Equals(R? other) anteriormente.The Equals method called by the == operator is the Equals(R? other) method specified above. El != operador delega en el == operador .The != operator delegates to the == operator. Es un error si los operadores se declaran explícitamente.It is an error if the operators are declared explicitly.
Si el tipo de registro se deriva de un tipo de registro base , el tipo de registro incluye una invalidación sintetizada equivalente a un método declarado de Base la siguiente manera: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);
Es un error si la invalidación se declara explícitamente.It is an error if the override is declared explicitly. Es un error si el método no invalida un método con la misma firma en el tipo de registro (por ejemplo, si falta el método en , o está sellado, o no Base Base es virtual, 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 invalidación sintetizada devuelve Equals((object?)other) .The synthesized override returns Equals((object?)other).
El tipo de registro incluye una invalidación sintetizada equivalente a un método declarado de la siguiente manera:The record type includes a synthesized override equivalent to a method declared as follows:
public override bool Equals(object? obj);
Es un error si la invalidación se declara explícitamente.It is an error if the override is declared explicitly. Es un error si el método no invalida (por ejemplo, debido al sombreado en tipos object.Equals(object? obj) base intermedios, 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 invalidación sintetizada devuelve Equals(other as R) donde es el tipo de R registro.The synthesized override returns Equals(other as R) where R is the record type.
El tipo de registro incluye una invalidación sintetizada equivalente a un método declarado de la siguiente manera:The record type includes a synthesized override equivalent to a method declared as follows:
public override int GetHashCode();
El método se puede declarar explícitamente.The method can be declared explicitly.
Es un error si la declaración explícita no permite invalidarla en un tipo derivado y el tipo de registro no es 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. Es un error si el método sintetizado o declarado explícitamente no invalida (por ejemplo, debido a la sombra en tipos object.GetHashCode() base intermedios, 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.).
Se notifica una advertencia si uno de Equals(R?) y GetHashCode() se declara explícitamente, pero el otro método no es explícito.A warning is reported if one of Equals(R?) and GetHashCode() is explicitly declared but the other method is not explicit.
La invalidación sintetizada GetHashCode() de devuelve un resultado de combinar los valores int siguientes:The synthesized override of GetHashCode() returns an int result of combining the following values:
- Para cada campo de instancia del tipo de registro que
fieldNno se hereda, el valor de where es el tipo de campoSystem.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)TNyFor each instance fieldfieldNin the record type that is not inherited, the value ofSystem.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)whereTNis the field type, and - Si hay un tipo de registro base, el valor de
base.GetHashCode(); de lo contrario, el valor deSystem.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract).If there is a base record type, the value ofbase.GetHashCode(); otherwise the value ofSystem.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract).
Por ejemplo, considere los siguientes tipos de registro: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);
Para esos tipos de registro, los miembros de igualdad sintetizados serían algo parecido a lo siguiente: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));
}
}
Copiar y clonar miembrosCopy and Clone members
Un tipo de registro contiene dos miembros de copia:A record type contains two copying members:
- Constructor que toma un único argumento del tipo de registro.A constructor taking a single argument of the record type. Se conoce como "constructor de copia".It is referred to as a "copy constructor".
- Método "clone" de instancia sin parámetros público sintetizado con un nombre reservado del compiladorA synthesized public parameterless instance "clone" method with a compiler-reserved name
El propósito del constructor de copia es copiar el estado del parámetro en la nueva instancia que se va a crear.The purpose of the copy constructor is to copy the state from the parameter to the new instance being created. Este constructor no ejecuta ningún inicializador de campo o propiedad de instancia presente en la declaración de registro.This constructor doesn't run any instance field/property initializers present in the record declaration. Si el constructor no se declara explícitamente, el compilador sintetizará un constructor.If the constructor is not explicitly declared, a constructor will be synthesized by the compiler. Si el registro está sellado, el constructor será privado; de lo contrario, se protegerá.If the record is sealed, the constructor will be private, otherwise it will be protected. Un constructor de copia declarado explícitamente debe ser público o protegido, a menos que el registro esté sellado.An explicitly declared copy constructor must be either public or protected, unless the record is sealed. Lo primero que debe hacer el constructor es llamar a un constructor de copia de la base o a un constructor de objetos sin parámetros si el registro hereda del objeto .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. Se notifica un error si un constructor de copia definido por el usuario usa un inicializador de constructor implícito o explícito que no cumple este requisito.An error is reported if a user-defined copy constructor uses an implicit or explicit constructor initializer that doesn't fulfill this requirement. Después de invocar un constructor de copia base, un constructor de copia sintetizado copia los valores de todos los campos de instancia declarados implícita o explícitamente dentro del tipo de registro.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 única presencia de un constructor de copia, ya sea explícita o implícita, no impide la adición automática de un constructor de instancia predeterminado.The sole presence of a copy constructor, whether explicit or implicit, doesn't prevent an automatic addition of a default instance constructor.
Si hay un método virtual "clone" en el registro base, el método "clone" sintetizado lo invalida y el tipo de valor devuelto del método es el tipo que contiene actualmente si se admite la característica "covariante returns" y, en caso contrario, el tipo de valor devuelto de invalidación.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. Se produce un error si el método de clonación del registro base está sellado.An error is produced if the base record clone method is sealed. Si un método virtual "clone" no está presente en el registro base, el tipo de valor devuelto del método clone es el tipo que lo contiene y el método es virtual, a menos que el registro sea sealed o 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 el registro que lo contiene es abstracto, el método clonado sintetizado también es abstracto.If the containing record is abstract, the synthesized clone method is also abstract. Si el método "clone" no es abstracto, devuelve el resultado de una llamada a un constructor de copia.If the "clone" method is not abstract, it returns the result of a call to a copy constructor.
Miembros de impresión: métodos PrintMembers y ToStringPrinting members: PrintMembers and ToString methods
Si el registro se deriva de , el registro incluye un método sintetizado object equivalente a un método declarado de la siguiente manera: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);
El método es private si el tipo de registro es sealed .The method is private if the record type is sealed. De lo contrario, el método es virtual y protected .Otherwise, the method is virtual and protected.
El método:The method:
- para cada uno de los miembros imprimibles del registro (campo público no estático y miembros de propiedad legible), anexa el nombre de ese miembro seguido de " = " seguido del valor del miembro separado por ", ",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 ", ",
- devuelve true si el registro tiene miembros imprimibles.return true if the record has printable members.
Para un miembro que tiene un tipo de valor, convertiremos su valor en una representación de cadena mediante el método más eficaz disponible para la plataforma de destino.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. En la actualidad eso significa llamar ToString a antes de pasar a StringBuilder.Append .At present that means calling ToString before passing to StringBuilder.Append.
Si el tipo de registro se deriva de un registro base , el registro incluye una invalidación sintetizada equivalente a un método declarado de Base la siguiente manera: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 el registro no tiene miembros imprimibles, el método llama al método base con PrintMembers un argumento (su parámetro) y devuelve el builder resultado.If the record has no printable members, the method calls the base PrintMembers method with one argument (its builder parameter) and returns the result.
De lo contrario, el método :Otherwise, the method:
- llama al método base
PrintMemberscon un argumento (su parámetrobuilder),calls the basePrintMembersmethod with one argument (itsbuilderparameter), - si el
PrintMembersmétodo devolvió true, anexe ", " al generador,if thePrintMembersmethod returned true, append ", " to the builder, - para cada uno de los miembros imprimibles del registro, anexa el nombre de ese miembro seguido de " = " seguido del valor del miembro: (o para los tipos de valor), separados por
this.memberthis.member.ToString()", ",for each of the record's printable members, appends that member's name followed by " = " followed by the member's value:this.member(orthis.member.ToString()for value types), separated with ", ", - devuelve true.return true.
El PrintMembers método se puede declarar explícitamente.The PrintMembers method can be declared explicitly.
Es un error si la declaración explícita no coincide con la firma o accesibilidad esperada, o si la declaración explícita no permite invalidarla en un tipo derivado y el tipo de registro no es 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.
El registro incluye un método sintetizado equivalente a un método declarado de la siguiente manera:The record includes a synthesized method equivalent to a method declared as follows:
public override string ToString();
El método se puede declarar explícitamente.The method can be declared explicitly. Es un error si la declaración explícita no coincide con la firma o accesibilidad esperada, o si la declaración explícita no permite reemplazarla en un tipo derivado y el tipo de registro no es 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. Es un error si el método sintetizado o declarado explícitamente no invalida (por ejemplo, debido a la sombra en tipos object.ToString() base intermedios, 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.).
Método sintetizado:The synthesized method:
- crea una
StringBuilderinstancia de ,creates aStringBuilderinstance, - anexa el nombre del registro al generador, seguido de " { ",appends the record name to the builder, followed by " { ",
- invoca el método del registro
PrintMembersque le da el generador, seguido de "" si devuelve true,invokes the record'sPrintMembersmethod giving it the builder, followed by " " if it returned true, - anexa "}",appends "}",
- devuelve el contenido del generador con
builder.ToString().returns the builder's contents withbuilder.ToString().
Por ejemplo, considere los siguientes tipos de registro:For example, consider the following record types:
record R1(T1 P1);
record R2(T1 P1, T2 P2, T3 P3) : R1(P1);
Para esos tipos de registro, los miembros de impresión sintetizados serían algo parecido a lo siguiente: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();
}
}
Miembros de registros posicionalesPositional record members
Además de los miembros anteriores, los registros con una lista de parámetros ("registros posicionales") sintetizan miembros adicionales con las mismas condiciones que los miembros anteriores.In addition to the above members, records with a parameter list ("positional records") synthesize additional members with the same conditions as the members above.
Constructor principalPrimary Constructor
Un tipo de registro tiene un constructor público cuya firma corresponde a los parámetros de valor de la declaración de tipo.A record type has a public constructor whose signature corresponds to the value parameters of the type declaration. Esto se denomina constructor principal para el tipo y hace que se suprima el constructor de clase predeterminado declarado implícitamente, si está presente.This is called the primary constructor for the type, and causes the implicitly declared default class constructor, if present, to be suppressed. Es un error tener un constructor principal y un constructor con la misma firma ya presente en la clase .It is an error to have a primary constructor and a constructor with the same signature already present in the class.
En tiempo de ejecución, el constructor principalAt runtime the primary constructor
ejecuta los inicializadores de instancia que aparecen en el cuerpo de claseexecutes the instance initializers appearing in the class-body
invoca el constructor de clase base con los argumentos proporcionados en la
record_basecláusula , si está presente.invokes the base class constructor with the arguments provided in therecord_baseclause, if present
Si un registro tiene un constructor principal, cualquier constructor definido por el usuario, excepto "constructor de copia", debe tener un this inicializador de constructor explícito.If a record has a primary constructor, any user-defined constructor, except "copy constructor" must have an explicit this constructor initializer.
Los parámetros del constructor principal, así como los miembros del registro, están dentro del ámbito de la cláusula y dentro de inicializadores de argument_list propiedades o campos de record_base instancia.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. Los miembros de instancia serían un error en estas ubicaciones (similar a la forma en que los miembros de instancia están en el ámbito en los inicializadores de constructor normales hoy en día, pero un error que se debe usar), pero los parámetros del constructor principal estarían en el ámbito y se pueden usar y sombrearía a los miembros.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. Los miembros estáticos también serían utilizables, de forma similar a cómo funcionan las llamadas base y los inicializadores en constructores normales hoy en día.Static members would also be useable, similar to how base calls and initializers work in ordinary constructors today.
Se genera una advertencia si no se lee un parámetro del constructor principal.A warning is produced if a parameter of the primary constructor is not read.
Las variables de expresión declaradas en argument_list están en el ámbito dentro de argument_list .Expression variables declared in the argument_list are in scope within the argument_list. Se aplican las mismas reglas de sombreado que en una lista de argumentos de un inicializador de constructor normal.The same shadowing rules as within an argument list of a regular constructor initializer apply.
PropiedadesProperties
Para cada parámetro de registro de una declaración de tipo de registro hay un miembro de propiedad pública correspondiente cuyo nombre y tipo se toman de la declaración de parámetro value.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.
Para un registro:For a record:
- Se crea
getuna propiedad pública y automáticainit(consulte lainitespecificación del accessor independiente).A publicgetandinitauto-property is created (see separateinitaccessor specification). Se invalida unaabstractpropiedad heredada con el tipo correspondiente.An inheritedabstractproperty with matching type is overridden. Es un error si la propiedad heredada no tiene lospublicgetinitaccessors y reemplazables.It is an error if the inherited property does not havepublicoverridablegetandinitaccessors. Es un error si la propiedad heredada está oculta.It is an error if the inherited property is hidden.
La propiedad automática se inicializa en el valor del parámetro de constructor principal correspondiente.The auto-property is initialized to the value of the corresponding primary constructor parameter. Los atributos se pueden aplicar a la propiedad automática sintetizada y a su campo de respaldo mediante el uso de destinos o para atributos aplicados sintácticamente alproperty:field:parámetro de registro correspondiente.Attributes can be applied to the synthesized auto-property and its backing field by usingproperty:orfield:targets for attributes syntactically applied to the corresponding record parameter.
DeconstruirDeconstruct
Un registro posicional con al menos un parámetro sintetiza un método de instancia público que devuelve void denominado Deconstruct con una declaración de parámetro out para cada parámetro de la declaración del constructor 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. Cada parámetro del método Deconstruct tiene el mismo tipo que el parámetro correspondiente de la declaración del constructor principal.Each parameter of the Deconstruct method has the same type as the corresponding parameter of the primary constructor declaration. El cuerpo del método asigna cada parámetro del método Deconstruct al valor de acceso de un miembro de instancia a un miembro del mismo nombre.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. El método se puede declarar explícitamente.The method can be declared explicitly. Es un error si la declaración explícita no coincide con la firma o accesibilidad esperada, o si es estática.It is an error if the explicit declaration does not match the expected signature or accessibility, or is static.
Expresión withwith expression
Una with expresión es una expresión nueva que usa la sintaxis siguiente.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
;
No with se permite una expresión como una instrucción .A with expression is not permitted as a statement.
Una expresión permite una "mutación no destructiva", diseñada para generar una copia de la expresión receptora con modificaciones en with las asignaciones en 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.
Una expresión with válida tiene un receptor con un tipo distinto de void.A valid with expression has a receiver with a non-void type. El tipo de receptor debe ser un registro.The receiver type must be a record.
En el lado derecho de la expresión hay un con una secuencia de asignaciones al identificador , que debe ser un campo de instancia accesible o una propiedad del tipo with member_initializer_list del receptor. 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.
En primer lugar, se invoca el método "clone" del receptor (especificado anteriormente) y su resultado se convierte al tipo del receptor.First, receiver's "clone" method (specified above) is invoked and its result is converted to the receiver's type. A continuación, cada uno de ellos se procesa de la misma manera que una asignación a un campo o acceso member_initializer de propiedad del resultado de la conversión.Then, each member_initializer is processed the same way as an assignment to a field or property access of the result of the conversion. Las asignaciones se procesan en orden léxico.Assignments are processed in lexical order.