DatensätzeRecords
Dieser Vorschlag verfolgt die Spezifikation für das C#9-Datensatzfeature nach, wie vom C#-Sprachentwurfsteam vereinbart.This proposal tracks the specification for the C# 9 records feature, as agreed to by the C# language design team.
Die Syntax für einen Datensatz lautet wie folgt: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* '}' ';'?
| ';'
;
Datensatztypen sind Verweistypen, die einer Klassendeklaration ähneln.Record types are reference types, similar to a class declaration. Es ist ein Fehler für einen Datensatz, einen -Eintrag zur Verfügung zu record_base
argument_list
stellen, record_declaration
wenn nicht parameter_list
enthält.It is an error for a record to provide a record_base
argument_list
if the record_declaration
does not contain a parameter_list
.
Eine partielle Typdeklaration eines partiellen Datensatzes kann nur eine parameter_list
bereitstellen.At most one partial type declaration of a partial record may provide a parameter_list
.
Datensatzparameter können nicht ref
die Modifizierer , oder out
verwenden this
(aber und sind in
params
zulässig).Record parameters cannot use ref
, out
or this
modifiers (but in
and params
are allowed).
VererbungInheritance
Datensätze können nicht von Klassen erben, es sei denn, die Klasse ist object
, und Klassen können nicht von Datensätzen erben.Records cannot inherit from classes, unless the class is object
, and classes cannot inherit from records. Datensätze können von anderen Datensätzen erben.Records can inherit from other records.
Member eines DatensatztypsMembers of a record type
Zusätzlich zu den im Datensatzkörper deklarierten Membern verfügt ein Datensatztyp über zusätzliche synthetisierte Member.In addition to the members declared in the record body, a record type has additional synthesized members. Member werden synthetisiert, es sei denn, ein Member mit einer "übereinstimmenden" Signatur wird im Datensatzkörper deklariert, oder ein zugänglicher konkretes nicht virtuelles Member mit einer "übereinstimmenden" Signatur wird geerbt.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. Zwei Member werden als übereinstimmend betrachtet, wenn sie dieselbe Signatur haben oder in einem Vererbungsszenario als "ausblendend" betrachtet werden.Two members are considered matching if they have the same signature or would be considered "hiding" in an inheritance scenario. Es ist ein Fehler, wenn ein Member eines Datensatzes den Namen "Clone" hat.It is an error for a member of a record to be named "Clone". Es ist ein Fehler, wenn ein Instanzfeld eines Datensatzes einen unsicheren Typ auf hat.It is an error for an instance field of a record to have an unsafe type.
Die synthetisierten Member lauten wie folgt:The synthesized members are as follows:
GleichheitsmitgliederEquality members
Wenn der Datensatz von abgeleitet wird, enthält der Datensatztyp eine synthetisierte schreibgeschützte Eigenschaft, die einer wie folgt deklarierten object
Eigenschaft entspricht: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; };
Die -Eigenschaft ist private
, wenn der Datensatztyp sealed
ist.The property is private
if the record type is sealed
. Andernfalls ist die -Eigenschaft virtual
und protected
.Otherwise, the property is virtual
and protected
.
Die -Eigenschaft kann explizit deklariert werden.The property can be declared explicitly. Dies ist ein Fehler, wenn die explizite Deklaration nicht mit der erwarteten Signatur oder dem erwarteten Zugriff übereinstimmt oder wenn die explizite Deklaration das Überschreiben in einem abgeleiteten Typ nicht zulässt und der Datensatztyp nicht sealed
ist.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
.
Wenn der Eintragstyp von einem Basisdatensatztyp abgeleitet Base
ist, enthält der Eintragstyp eine synthetisierte schreibgeschützte Eigenschaft, die einer wie folgt deklarierten Eigenschaft entspricht: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; };
Die -Eigenschaft kann explizit deklariert werden.The property can be declared explicitly. Dies ist ein Fehler, wenn die explizite Deklaration nicht mit der erwarteten Signatur oder dem erwarteten Zugriff übereinstimmt oder wenn die explizite Deklaration das Überschreiben in einem abgeleiteten Typ nicht zulässt und der Datensatztyp nicht sealed
ist.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
. Dies ist ein Fehler, wenn entweder eine synthetisierte oder explizit deklarierte Eigenschaft eine Eigenschaft mit dieser Signatur im Datensatztyp nicht überschreibt Base
(z. B. wenn die Eigenschaft in Base
fehlt, oder versiegelt oder nicht virtuell usw.).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.).
Die synthetisierte Eigenschaft gibt typeof(R)
zurück, wobei R
der Datensatztyp ist.The synthesized property returns typeof(R)
where R
is the record type.
Der Datensatztyp implementiert System.IEquatable<R>
und enthält eine synthetisierte stark typisierte Überladung von Equals(R? other)
, wobei der R
Datensatztyp ist.The record type implements System.IEquatable<R>
and includes a synthesized strongly-typed overload of Equals(R? other)
where R
is the record type.
Die -Methode ist public
, und die -Methode ist , es virtual
sei denn, der Datensatztyp ist sealed
.The method is public
, and the method is virtual
unless the record type is sealed
.
Die -Methode kann explizit deklariert werden.The method can be declared explicitly. Dies ist ein Fehler, wenn die explizite Deklaration nicht mit der erwarteten Signatur oder dem erwarteten Zugriff übereinstimmt oder die explizite Deklaration das Überschreiben in einem abgeleiteten Typ nicht zulässt und der Datensatztyp nicht sealed
ist.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
.
Wenn Equals(R? other)
benutzerdefinierter (nicht synthetisierter) ist, aber GetHashCode
nicht, wird eine Warnung erzeugt.If Equals(R? other)
is user-defined (not synthesized) but GetHashCode
is not, a warning is produced.
public virtual bool Equals(R? other);
Der synthetisierte Equals(R?)
gibt true
nur dann zurück, wenn jede der folgenden true
ist:The synthesized Equals(R?)
returns true
if and only if each of the following are true
:
other
ist nichtnull
, undother
is notnull
, and- Für jedes Instanzfeld
fieldN
im Datensatztyp, das nicht geerbt wird, ist der Wert vonSystem.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)
, wobei derTN
Feldtyp ist, undFor each instance fieldfieldN
in the record type that is not inherited, the value ofSystem.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)
whereTN
is the field type, and - Wenn ein Basisdatensatztyp vorhanden ist, der Wert von
base.Equals(other)
(ein nicht virtueller Aufrufpublic virtual bool Equals(Base? other)
von ), andernfalls der Wert vonEqualityContract == 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
.
Der Datensatztyp enthält synthetisierte ==
Operatoren und !=
Operatoren, die operatoren entsprechen, die wie folgt deklariert sind: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);
Die Equals
vom -Operator ==
aufgerufene Methode ist die oben angegebene Equals(R? other)
Methode.The Equals
method called by the ==
operator is the Equals(R? other)
method specified above. Der !=
Operator delegiert an den ==
Operator.The !=
operator delegates to the ==
operator. Es ist ein Fehler, wenn die Operatoren explizit deklariert werden.It is an error if the operators are declared explicitly.
Wenn der Datensatztyp von einem Basisdatensatztyp abgeleitet wird, enthält der Datensatztyp eine synthetisierte Überschreibung, die einer wie folgt Base
deklarierten Methode entspricht: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 ist ein Fehler, wenn die Überschreibung explizit deklariert wird.It is an error if the override is declared explicitly. Es ist ein Fehler, wenn die Methode eine Methode mit derselben Signatur im Datensatztyp nicht überschreibt (z. B. wenn die Methode in fehlt, oder versiegelt oder nicht virtuell Base
Base
usw.).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.).
Die synthetisierte Überschreibung gibt Equals((object?)other)
zurück.The synthesized override returns Equals((object?)other)
.
Der Datensatztyp enthält eine synthetisierte Überschreibung, die einer wie folgt deklarierten Methode entspricht:The record type includes a synthesized override equivalent to a method declared as follows:
public override bool Equals(object? obj);
Es ist ein Fehler, wenn die Überschreibung explizit deklariert wird.It is an error if the override is declared explicitly. Es ist ein Fehler, wenn die Methode nicht überschreibt (z. B. aufgrund von Schatten in Zwischenbasistypen object.Equals(object? obj)
usw.).It is an error if the method doesn't override object.Equals(object? obj)
(for example, due to shadowing in intermediate base types, etc.).
Die synthetisierte Überschreibung gibt Equals(other as R)
zurück, R
wobei der Datensatztyp ist.The synthesized override returns Equals(other as R)
where R
is the record type.
Der Datensatztyp enthält eine synthetisierte Überschreibung, die einer wie folgt deklarierten Methode entspricht:The record type includes a synthesized override equivalent to a method declared as follows:
public override int GetHashCode();
Die -Methode kann explizit deklariert werden.The method can be declared explicitly.
Es ist ein Fehler, wenn die explizite Deklaration das Überschreiben in einem abgeleiteten Typ nicht zu lässt und der Datensatztyp nicht sealed
ist.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 ist ein Fehler, wenn die synthetisierte oder explizit deklarierte Methode nicht überschrieben wird (z. B. aufgrund von Schatten in Zwischenbasistypen object.GetHashCode()
usw.).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.).
Eine Warnung wird gemeldet, wenn eine von Equals(R?)
und GetHashCode()
explizit deklariert ist, die andere Methode jedoch nicht explizit ist.A warning is reported if one of Equals(R?)
and GetHashCode()
is explicitly declared but the other method is not explicit.
Die synthetisierte Überschreibung GetHashCode()
von gibt ein Ergebnis der Kombination der folgenden Werte int
zurück:The synthesized override of GetHashCode()
returns an int
result of combining the following values:
- Für jedes Instanzfeld im Datensatztyp, das nicht geerbt wird, ist der Wert von , wobei
fieldN
System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)
derTN
Feldtyp ist, undFor each instance fieldfieldN
in the record type that is not inherited, the value ofSystem.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)
whereTN
is the field type, and - Wenn ein Basisdatensatztyp vor liegt, der Wert von
base.GetHashCode()
, andernfalls der Wert vonSystem.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)
.
Betrachten Sie beispielsweise die folgenden Datensatztypen: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);
Für diese Datensatztypen würden die synthetisierten Gleichheitsmember in etwa wie folgt aussehen: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));
}
}
Methoden zum Kopieren und Klonen von MembernCopy and Clone members
Ein Datensatztyp enthält zwei Kopiermember:A record type contains two copying members:
- Ein Konstruktor, der ein einzelnes Argument des Datensatztyps annimmt.A constructor taking a single argument of the record type. Er wird als "Kopierkonstruktor" bezeichnet.It is referred to as a "copy constructor".
- Eine synthetisierte methode zum Klonen einer öffentlichen parameterlosen Instanz mit einem vom Compiler reservierten NamenA synthesized public parameterless instance "clone" method with a compiler-reserved name
Der Zweck des Kopierkonstruktors besteht darin, den Zustand aus dem Parameter in die neue Instanz zu kopieren, die erstellt wird.The purpose of the copy constructor is to copy the state from the parameter to the new instance being created. Dieser Konstruktor führt keine Instanzfeld-/Eigenschafteninitialisierer aus, die in der Datensatzdeklaration vorhanden sind.This constructor doesn't run any instance field/property initializers present in the record declaration. Wenn der Konstruktor nicht explizit deklariert wird, wird ein Konstruktor vom Compiler synthetisiert.If the constructor is not explicitly declared, a constructor will be synthesized by the compiler. Wenn der Datensatz versiegelt ist, ist der Konstruktor privat, andernfalls wird er geschützt.If the record is sealed, the constructor will be private, otherwise it will be protected. Ein explizit deklarierter Kopierkonstruktor muss entweder öffentlich oder geschützt sein, es sei denn, der Datensatz ist versiegelt.An explicitly declared copy constructor must be either public or protected, unless the record is sealed. Zunächst muss der Konstruktor einen Kopierkonstruktor der Basis oder einen parameterfreien Objektkonstruktor aufrufen, wenn der Datensatz vom Objekt erbt.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. Ein Fehler wird gemeldet, wenn ein benutzerdefinierter Kopierkonstruktor einen impliziten oder expliziten Konstruktorinitialisierer verwendet, der diese Anforderung nicht erfüllt.An error is reported if a user-defined copy constructor uses an implicit or explicit constructor initializer that doesn't fulfill this requirement. Nachdem ein Basiskopierkonstruktor aufgerufen wurde, kopiert ein synthetisierter Kopierkonstruktor Werte für alle Instanzfelder, die implizit oder explizit innerhalb des Datensatztyps deklariert sind.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. Das ausschließliche Vorhandensein eines Kopierkonstruktors , ob explizit oder implizit, verhindert nicht das automatische Hinzufügen eines Standardinstanzkonstruktors.The sole presence of a copy constructor, whether explicit or implicit, doesn't prevent an automatic addition of a default instance constructor.
Wenn eine virtuelle Klonmethode im Basisdatensatz vorhanden ist, überschreibt die synthetisierte Klonmethode sie, und der Rückgabetyp der Methode ist der aktuelle enthaltende Typ, wenn das Feature "kovariant returns" unterstützt wird und der Rückgabetyp andernfalls den Rückgabetyp überschreibt.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. Wenn die Klonmethode des Basisdatensatzes versiegelt ist, wird ein Fehler erzeugt.An error is produced if the base record clone method is sealed. Wenn keine virtuelle Klonmethode im Basisdatensatz vorhanden ist, ist der Rückgabetyp der Klonmethode der enthaltende Typ und die Methode virtuell, es sei denn, der Datensatz ist versiegelt oder abstrakt.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. Wenn der enthaltende Datensatz abstrakt ist, ist die synthetisierte Klonmethode ebenfalls abstrakt.If the containing record is abstract, the synthesized clone method is also abstract. Wenn die "clone"-Methode nicht abstrakt ist, wird das Ergebnis eines Aufrufs eines Kopierkonstruktors zurückgegeben.If the "clone" method is not abstract, it returns the result of a call to a copy constructor.
Druckmember: PrintMembers- und ToString-MethodenPrinting members: PrintMembers and ToString methods
Wenn der Datensatz von abgeleitet wird, enthält der Datensatz eine synthetisierte Methode, die object
einer wie folgt deklarierten Methode entspricht: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);
Die -Methode ist private
, wenn der Datensatztyp sealed
ist.The method is private
if the record type is sealed
. Andernfalls ist die -Methode virtual
und protected
.Otherwise, the method is virtual
and protected
.
Die Methode führt Folgendes aus:The method:
- fügt für jeden druckbaren Member des Datensatzes (nicht statisches öffentliches Feld und lesbare Eigenschaftsmitglieder) den Namen dieses Members an, gefolgt von " = " gefolgt vom Wert des Members, der durch ", ",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 ", ",
- gibt TRUE zurück, wenn der Datensatz druckbare Member auf hat.return true if the record has printable members.
Für einen Member mit einem Werttyp konvertieren wir seinen Wert in eine Zeichenfolgendarstellung, indem wir die effizienteste Methode verwenden, die für die Zielplattform verfügbar ist.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. Derzeit bedeutet dies, dass vor ToString
der Übergabe an ein Aufruf von StringBuilder.Append
bedeutet.At present that means calling ToString
before passing to StringBuilder.Append
.
Wenn der Datensatztyp von einem Basisdatensatz abgeleitet wird, enthält der Datensatz eine synthetisierte Überschreibung, die einer wie folgt deklarierten Base
Methode entspricht: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);
Wenn der Datensatz über keine druckbaren Member verfügt, ruft die Methode die Basismethode mit einem Argument PrintMembers
(dessen Parameter) auf und gibt das Ergebnis builder
zurück.If the record has no printable members, the method calls the base PrintMembers
method with one argument (its builder
parameter) and returns the result.
Andernfalls ist die -Methode:Otherwise, the method:
- ruft die
PrintMembers
Basismethode mit einem Argument (dessenbuilder
Parameter) auf.calls the basePrintMembers
method with one argument (itsbuilder
parameter), - Wenn die
PrintMembers
Methode TRUE zurückgegeben hat, fügen Sie ", " an den Generator an.if thePrintMembers
method returned true, append ", " to the builder, - fügt für jedes druckbare Member des Datensatzes den Namen dieses Members an, gefolgt von " = " gefolgt vom Wert des Members: (oder für Werttypen), getrennt durch
this.member
this.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 ", ", - gibt TRUE zurück.return true.
Die PrintMembers
-Methode kann explizit deklariert werden.The PrintMembers
method can be declared explicitly.
Dies ist ein Fehler, wenn die explizite Deklaration nicht mit der erwarteten Signatur oder dem erwarteten Zugriff übereinstimmen, oder wenn die explizite Deklaration das Überschreiben in einem abgeleiteten Typ nicht zu lässt und der Datensatztyp nicht sealed
ist.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
.
Der Datensatz enthält eine synthetisierte Methode, die einer wie folgt deklarierten Methode entspricht:The record includes a synthesized method equivalent to a method declared as follows:
public override string ToString();
Die -Methode kann explizit deklariert werden.The method can be declared explicitly. Dies ist ein Fehler, wenn die explizite Deklaration nicht mit der erwarteten Signatur oder dem erwarteten Zugriff übereinstimmt oder wenn die explizite Deklaration das Überschreiben in einem abgeleiteten Typ nicht zulässt und der Datensatztyp nicht sealed
ist.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
. Dies ist ein Fehler, wenn entweder eine synthetisierte oder explizit deklarierte Methode nicht außer Kraft gesetzt wird object.ToString()
(z. B. aufgrund von Shadowing in zwischengeschalteten Basistypen usw.).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.).
Die synthetisierte Methode:The synthesized method:
- erstellt eine
StringBuilder
-Instanz,creates aStringBuilder
instance, - fügt den Eintragsnamen an den Generator an, gefolgt von " { ",appends the record name to the builder, followed by " { ",
- ruft die -Methode des Datensatzes auf
PrintMembers
und gibt ihm den Generator, gefolgt von " ", wenn true zurückgegeben wird.invokes the record'sPrintMembers
method giving it the builder, followed by " " if it returned true, - fügt "}" an,appends "}",
- gibt den Inhalt des Generators mit
builder.ToString()
zurück.returns the builder's contents withbuilder.ToString()
.
Betrachten Sie beispielsweise die folgenden Datensatztypen:For example, consider the following record types:
record R1(T1 P1);
record R2(T1 P1, T2 P2, T3 P3) : R1(P1);
Für diese Datensatztypen würden die synthetisierten Druckmember in etwa wie folgt aussehen: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();
}
}
Positional Record Members (Positional Record-Elemente)Positional record members
Zusätzlich zu den oben genannten Membern synthetisieren Datensätze mit einer Parameterliste ("Positionsdatensätze") zusätzliche Member mit denselben Bedingungen wie die oben genannten Member.In addition to the above members, records with a parameter list ("positional records") synthesize additional members with the same conditions as the members above.
Primärer KonstruktorPrimary Constructor
Ein Datensatztyp verfügt über einen öffentlichen Konstruktor, dessen Signatur den Wertparametern der Typdeklaration entspricht.A record type has a public constructor whose signature corresponds to the value parameters of the type declaration. Dies wird als primärer Konstruktor für den Typ bezeichnet und bewirkt, dass der implizit deklarierte Standardklassenkonstruktor unterdrückt wird, sofern vorhanden.This is called the primary constructor for the type, and causes the implicitly declared default class constructor, if present, to be suppressed. Es ist ein Fehler, einen primären Konstruktor und einen Konstruktor mit der gleichen Signatur zu haben, die bereits in der -Klasse vorhanden sind.It is an error to have a primary constructor and a constructor with the same signature already present in the class.
Zur Laufzeit der primäre KonstruktorAt runtime the primary constructor
führt die Instanzinitialisierer aus, die im Klassentext angezeigt werden.executes the instance initializers appearing in the class-body
ruft den Basisklassenkonstruktor mit den in der -Klausel bereitgestellten Argumenten
record_base
auf, sofern vorhanden.invokes the base class constructor with the arguments provided in therecord_base
clause, if present
Wenn ein Datensatz über einen primären Konstruktor verfügt, muss jeder benutzerdefinierte Konstruktor außer "Kopierkonstruktor" über einen expliziten this
Konstruktorinitialisierer verfügen.If a record has a primary constructor, any user-defined constructor, except "copy constructor" must have an explicit this
constructor initializer.
Parameter des primären Konstruktors sowie Member des Datensatzes befinden sich im Gültigkeitsbereich innerhalb der -Klausel und innerhalb von Initialisierern argument_list
record_base
von Instanzfeldern oder -eigenschaften.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. Instanzmitglieder wären an diesen Stellen ein Fehler (ähnlich wie Instanzmitglieder im Gültigkeitsbereich in regulären Konstruktorinitialisierern, aber ein Fehler, der verwendet werden sollte), aber die Parameter des primären Konstruktors würden sich im Gültigkeitsbereich befinden und verwendet werden und würden Member überschatten.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. Statische Member wären ebenfalls nutzbar, ähnlich wie Basisaufrufe und Initialisierer heute in normalen Konstruktoren funktionieren.Static members would also be useable, similar to how base calls and initializers work in ordinary constructors today.
Eine Warnung wird erzeugt, wenn ein Parameter des primären Konstruktors nicht gelesen wird.A warning is produced if a parameter of the primary constructor is not read.
Ausdrucksvariablen, die in der deklariert argument_list
werden, befinden sich innerhalb des argument_list
Bereichs.Expression variables declared in the argument_list
are in scope within the argument_list
. Es gelten die gleichen Schattenregeln wie in einer Argumentliste eines regulären Konstruktorinitialisierers.The same shadowing rules as within an argument list of a regular constructor initializer apply.
EigenschaftenProperties
Für jeden Datensatzparameter einer Datensatztypdeklaration gibt es einen entsprechenden member der öffentlichen Eigenschaft, dessen Name und Typ aus der Wertparameterdeklaration übernommen werden.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.
Für einen Datensatz:For a record:
- Eine öffentliche
get
und automatische Eigenschaft wird erstelltinit
(siehe separateinit
Accessorspezifikation).A publicget
andinit
auto-property is created (see separateinit
accessor specification). Eine geerbteabstract
Eigenschaft mit übereinstimmenden Typen wird überschrieben.An inheritedabstract
property with matching type is overridden. Es ist ein Fehler, wenn die geerbte Eigenschaft nicht überschreibbare - undpublic
get
init
-Accessoren verfügt.It is an error if the inherited property does not havepublic
overridableget
andinit
accessors. Es ist ein Fehler, wenn die geerbte Eigenschaft ausgeblendet ist.It is an error if the inherited property is hidden.
Die auto-Eigenschaft wird mit dem Wert des entsprechenden primären Konstruktorparameters initialisiert.The auto-property is initialized to the value of the corresponding primary constructor parameter. Attribute können auf die synthetisierte auto-Eigenschaft und das zugehörige Hintergrundfeld angewendet werden, indem - oder -Ziele für Attribute verwendet werden, die syntaktisch auf den entsprechendenproperty:
field:
Datensatzparameter angewendet werden.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.
DekonstruierenDeconstruct
Ein Positionsdatensatz mit mindestens einem Parameter synthetisiert eine öffentliche, void-zurückgebende Instanzmethode namens Deconstruct mit einer out-Parameterdeklaration für jeden Parameter der primären Konstruktordeklaration.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. Jeder Parameter der Deconstruct-Methode hat den gleichen Typ wie der entsprechende Parameter der primären Konstruktordeklaration.Each parameter of the Deconstruct method has the same type as the corresponding parameter of the primary constructor declaration. Der Text der Methode weist jedem Parameter der Deconstruct-Methode den Wert eines Instanzmemberzugriffs auf einen Member mit dem gleichen Namen zu.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. Die -Methode kann explizit deklariert werden.The method can be declared explicitly. Dies ist ein Fehler, wenn die explizite Deklaration nicht mit der erwarteten Signatur oder Barrierefreiheit übereinstimmt oder statisch ist.It is an error if the explicit declaration does not match the expected signature or accessibility, or is static.
with
-Ausdruckwith
expression
Ein with
Ausdruck ist ein neuer Ausdruck mit der folgenden Syntax.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
;
Ein with
Ausdruck ist als -Anweisung nicht zulässig.A with
expression is not permitted as a statement.
Ein with
Ausdruck ermöglicht eine "nicht destruktive Mutation", die entwickelt wurde, um eine Kopie des Empfängerausdrucks mit Änderungen in Zuweisungen im zu member_initializer_list
erstellen.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
.
Ein gültiger with
Ausdruck verfügt über einen Empfänger mit einem Nicht-Void-Typ.A valid with
expression has a receiver with a non-void type. Der Empfängertyp muss ein Datensatz sein.The receiver type must be a record.
Auf der rechten Seite des Ausdrucks befindet sich ein mit einer Sequenz von Zuweisungen zum Bezeichner . Dabei muss es sich with
member_initializer_list
um ein zugängliches Instanzfeld oder eine Eigenschaft des Empfängertyps handelt. 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.
Zuerst wird die Oben angegebene Klonmethode des Empfängers aufgerufen, und das Ergebnis wird in den Typ des Empfängers konvertiert.First, receiver's "clone" method (specified above) is invoked and its result is converted to the receiver's type. Anschließend wird jede auf member_initializer
die gleiche Weise verarbeitet wie eine Zuweisung zu einem Feld- oder Eigenschaftszugriff des Ergebnisses der Konvertierung.Then, each member_initializer
is processed the same way as an assignment to a field or property access of the result of the conversion. Zuweisungen werden in lexikalischer Reihenfolge verarbeitet.Assignments are processed in lexical order.