レコードRecords

この提案では、C# 言語設計チームによって合意された、C# 9 レコード機能の仕様を追跡します。This proposal tracks the specification for the C# 9 records feature, as agreed to by the C# language design team.

レコードの構文は次のとおりです。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* '}' ';'?
    | ';'
    ;

レコード型は、クラス宣言に似た参照型です。Record types are reference types, similar to a class declaration. にが含まれていない場合、レコードでを指定するとエラーになり record_base argument_list 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. 部分的なレコードの部分型宣言には、を1つだけ指定でき parameter_list ます。At most one partial type declaration of a partial record may provide a parameter_list.

レコードパラメーター ref では、または修飾子を使用できません out this (ただし in 、と params は許可されます)。Record parameters cannot use ref, out or this modifiers (but in and params are allowed).

継承Inheritance

クラスがではなく、クラスが object レコードから継承できない場合を除き、レコードはクラスから継承できません。Records cannot inherit from classes, unless the class is object, and classes cannot inherit from records. レコードは他のレコードから継承できます。Records can inherit from other records.

レコードの種類のメンバーMembers of a record type

レコードの種類には、レコードの本体で宣言されたメンバーに加えて、追加の合成されたメンバーがあります。In addition to the members declared in the record body, a record type has additional synthesized members. "一致する" シグネチャを持つメンバーがレコード本体で宣言されていない場合、または "一致する" シグネチャを持つアクセス可能な具象仮想メンバーが継承されていない場合は、メンバーが合成されます。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. 2つのメンバーが同じシグネチャを持つ場合、または継承シナリオで "非表示" と見なされる場合は、一致と見なされます。Two members are considered matching if they have the same signature or would be considered "hiding" in an inheritance scenario. レコードのメンバーが "Clone" という名前になっていると、エラーになります。It is an error for a member of a record to be named "Clone". レコードのインスタンスフィールドに安全でない型が含まれていると、エラーになります。It is an error for an instance field of a record to have an unsafe type.

合成されたメンバーは次のとおりです。The synthesized members are as follows:

等値メンバーEquality members

レコードがから派生している場合 object 、レコード型には、次のように宣言されたプロパティと等価の合成された読み取り専用プロパティが含まれます。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; };

レコードの種類がの場合、プロパティはです private sealedThe property is private if the record type is sealed. それ以外の場合、プロパティは virtual および protected です。Otherwise, the property is virtual and protected. プロパティは明示的に宣言できます。The property can be declared explicitly. 明示的な宣言が予期されるシグネチャまたはアクセシビリティと一致しない場合、または明示的な宣言で派生型でのオーバーライドが許可されておらず、レコード型がでない場合は、エラーになり 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.

レコード型が基本レコード型から派生している場合 Base 、レコード型には、次のように宣言されたプロパティと等価の合成された読み取り専用プロパティが含まれます。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; };

プロパティは明示的に宣言できます。The property can be declared explicitly. 明示的な宣言が予期されるシグネチャまたはアクセシビリティと一致しない場合、または明示的な宣言で派生型でのオーバーライドが許可されておらず、レコード型がでない場合は、エラーになり 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. 合成された、または明示的に宣言されたプロパティによって、レコードの種類でこのシグネチャを持つプロパティがオーバーライドされない場合 (たとえば、、、またはシールドされていない場合や、 Base 仮想でない場合など) は、エラーになり Base ます。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.). 合成されたプロパティはを返し typeof(R) R ます。ここで、はレコードの種類です。The synthesized property returns typeof(R) where R is the record type.

レコード型は System.IEquatable<R> を実装し、の厳密に型指定された合成オーバーロードを含み Equals(R? other) R ます。ここで、はレコードの種類です。The record type implements System.IEquatable<R> and includes a synthesized strongly-typed overload of Equals(R? other) where R is the record type. メソッドは public で、 virtual レコードの種類がでない場合、メソッドはです sealedThe method is public, and the method is virtual unless the record type is sealed. メソッドは、明示的に宣言できます。The method can be declared explicitly. 明示的な宣言が予期されるシグネチャまたはアクセシビリティと一致しない場合、または明示的な宣言によって派生型でのオーバーライドが許可されておらず、レコード型がでない場合は、エラーになり 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.

Equals(R? other)がユーザー定義 (合成されていない) の場合 GetHashCode 、警告が生成されます。If Equals(R? other) is user-defined (not synthesized) but GetHashCode is not, a warning is produced.

public virtual bool Equals(R? other);

合成されたは、 Equals(R?) true 次の各がの場合にのみを返し true ます。The synthesized Equals(R?) returns true if and only if each of the following are true:

  • other がではなく nullother is not null, and
  • 継承されていないレコードの種類の各インスタンスフィールドについて fieldN 、の値は System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN) TN フィールド型になります。For 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
  • 基本レコードの種類がある場合は、の値 base.Equals(other) (への非仮想呼び出し)、それ以外の場合は public virtual bool Equals(Base? other) の値 EqualityContract == other.EqualityContractIf 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.

レコード型には、次のように宣言された == != 演算子に相当する合成および演算子が含まれます。The record type includes synthesized == and != operators equivalent to operators declared as follows:

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

Equals演算子によって呼び出されるメソッド == は、上で Equals(R? other) 指定されたメソッドです。The Equals method called by the == operator is the Equals(R? other) method specified above. 演算子は != 演算子にデリゲートし == ます。The != operator delegates to the == operator. 演算子が明示的に宣言されている場合、エラーになります。It is an error if the operators are declared explicitly.

レコード型が基本レコード型から派生している場合 Base 、レコード型には、次のように宣言されたメソッドに相当する合成オーバーライドが含まれます。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);

オーバーライドが明示的に宣言されている場合、エラーになります。It is an error if the override is declared explicitly. メソッドがレコードの種類で同じシグネチャを持つメソッドをオーバーライドしない場合 Base (たとえば、メソッドが、、またはシールドされていない場合や、仮想でない場合など)、エラーになり Base ます。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.). 合成されたオーバーライドはを返し Equals((object?)other) ます。The synthesized override returns Equals((object?)other).

レコード型には、次のように宣言されたメソッドに相当する合成オーバーライドが含まれます。The record type includes a synthesized override equivalent to a method declared as follows:

public override bool Equals(object? obj);

オーバーライドが明示的に宣言されている場合、エラーになります。It is an error if the override is declared explicitly. メソッドがオーバーライドしない場合 object.Equals(object? obj) (たとえば、中間の基本型のシャドウが原因で)、エラーになります。It is an error if the method doesn't override object.Equals(object? obj) (for example, due to shadowing in intermediate base types, etc.). 合成されたオーバーライドはを返し Equals(other as R) R ます。ここで、はレコードの種類です。The synthesized override returns Equals(other as R) where R is the record type.

レコード型には、次のように宣言されたメソッドに相当する合成オーバーライドが含まれます。The record type includes a synthesized override equivalent to a method declared as follows:

public override int GetHashCode();

メソッドは、明示的に宣言できます。The method can be declared explicitly. 明示的な宣言で派生型でのオーバーライドが許可されておらず、レコード型がではない場合、エラーになり 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. 合成された、または明示的に宣言されたメソッドがオーバーライドしない場合 object.GetHashCode() (たとえば、中間の基本型のシャドウが原因で)、エラーになります。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.).

とのいずれかが明示的に宣言されているが、 Equals(R?) GetHashCode() 他のメソッドが明示的ではない場合、警告が報告されます。A warning is reported if one of Equals(R?) and GetHashCode() is explicitly declared but the other method is not explicit.

の合成されたオーバーライドは、 GetHashCode() int 次の値を組み合わせた決定的関数の結果を返します。The synthesized override of GetHashCode() returns an int result of a deterministic function combining the following values:

  • 継承されていないレコードの種類の各インスタンスフィールドについて fieldN 、の値は System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN) TN フィールド型になります。For 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
  • 基本レコード型がの場合はの値、それ以外の場合は base.GetHashCode() の値 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).

たとえば、次のレコードの種類について考えてみます。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);

これらのレコードの種類では、合成された等値のメンバーは次のようになります。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? r1, R1? r2)
        => (object)r1 == r2 || (r1?.Equals(r2) ?? false);
    public static bool operator!=(R1? r1, R1? r2)
        => !(r1 == r2);    
    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? r1, R2? r2)
        => (object)r1 == r2 || (r1?.Equals(r2) ?? false);
    public static bool operator!=(R2? r1, R2? r2)
        => !(r1 == r2);    
    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? r1, R3? r2)
        => (object)r1 == r2 || (r1?.Equals(r2) ?? false);
    public static bool operator!=(R3? r1, R3? r2)
        => !(r1 == r2);    
    public override int GetHashCode()
    {
        return Combine(base.GetHashCode(),
            EqualityComparer<T3>.Default.GetHashCode(P3));
    }
}

コピー メンバーとクローン メンバーCopy and Clone members

レコード型には、2つのコピーメンバーが含まれています。A record type contains two copying members:

  • レコード型の単一の引数を受け取るコンストラクター。A constructor taking a single argument of the record type. これは "コピーコンストラクター" と呼ばれます。It is referred to as a "copy constructor".
  • コンパイラに予約された名前を持つ、合成されたパブリックパラメーターなしインスタンス "clone" メソッドA synthesized public parameterless instance "clone" method with a compiler-reserved name

コピーコンストラクターの目的は、パラメーターから作成される新しいインスタンスに状態をコピーすることです。The purpose of the copy constructor is to copy the state from the parameter to the new instance being created. このコンストラクターは、レコード宣言に存在するインスタンスフィールドやプロパティ初期化子を実行しません。This constructor doesn't run any instance field/property initializers present in the record declaration. コンストラクターが明示的に宣言されていない場合、コンストラクターはコンパイラによって合成されます。If the constructor is not explicitly declared, a constructor will be synthesized by the compiler. レコードがシールされている場合、コンストラクターはプライベートになり、それ以外の場合は保護されます。If the record is sealed, the constructor will be private, otherwise it will be protected. 明示的に宣言されたコピーコンストラクターは、レコードがシールされていない限り、public または protected でなければなりません。An explicitly declared copy constructor must be either public or protected, unless the record is sealed. コンストラクターが最初に行う必要があるのは、基本のコピーコンストラクターを呼び出すか、レコードがオブジェクトから継承している場合はパラメーターのないオブジェクトコンストラクターを呼び出すことです。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. ユーザー定義のコピーコンストラクターが、この要件を満たさない暗黙的または明示的なコンストラクター初期化子を使用すると、エラーが報告されます。An error is reported if a user-defined copy constructor uses an implicit or explicit constructor initializer that doesn't fulfill this requirement. 基本コピーコンストラクターが呼び出されると、合成コピーコンストラクターは、レコード型内で暗黙的または明示的に宣言されたすべてのインスタンスフィールドの値をコピーします。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. 明示的か暗黙的かにかかわらず、コピーコンストラクターが存在するだけでは、既定のインスタンスコンストラクターが自動的に追加されるのを防ぐことはできません。The sole presence of a copy constructor, whether explicit or implicit, doesn't prevent an automatic addition of a default instance constructor.

仮想 "clone" メソッドが基本レコードに存在する場合、合成された "clone" メソッドはそれをオーバーライドし、"共変の戻り値" 機能がサポートされている場合は、メソッドの戻り値の型が現在の格納型になり、それ以外の場合は戻り値の型がオーバーライドされます。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. ベースレコードの複製メソッドが封印されていると、エラーが生成されます。An error is produced if the base record clone method is sealed. 仮想 "clone" メソッドが基本レコードに存在しない場合、clone メソッドの戻り値の型はそれを含む型であり、メソッドは仮想であり、レコードが sealed または 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. 含まれているレコードが abstract の場合、合成された複製メソッドも抽象になります。If the containing record is abstract, the synthesized clone method is also abstract. "Clone" メソッドが abstract でない場合は、コピーコンストラクターへの呼び出しの結果を返します。If the "clone" method is not abstract, it returns the result of a call to a copy constructor.

メンバーの印刷: PrintMembers と ToString メソッドPrinting members: PrintMembers and ToString methods

レコードがから派生している場合 object 、レコードには、次のように宣言されたメソッドに相当する、合成されたメソッドが含まれます。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);

レコードの種類がの場合、メソッドはです private sealedThe method is private if the record type is sealed. それ以外の場合、メソッドは virtualprotected です。Otherwise, the method is virtual and protected.

このメソッドでは、次の操作を行います。The method:

  1. レコードの印刷可能な各メンバー (静的でないパブリックフィールドと読み取り可能なプロパティメンバー) について、によって、そのメンバーの名前の後に "=" が付加され、その後にメンバーの値が追加されます。これは、 this.member "," で区切られます。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: this.member, separated with ", ",
  2. レコードに印刷可能なメンバーがある場合は true を返します。return true if the record has printable members.

レコードの種類が基本レコードから派生している場合、レコードには、 Base 次のように宣言されたメソッドに相当する合成されたオーバーライドが含まれます。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);

レコードに印刷可能なメンバーがない場合、メソッドは PrintMembers 1 つの引数 (パラメーター) を使用して基本メソッドを呼び出し、 builder 結果を返します。If the record has no printable members, the method calls the base PrintMembers method with one argument (its builder parameter) and returns the result.

それ以外の場合、メソッドは次のようになります。Otherwise, the method:

  1. PrintMembers1 つの引数 (そのパラメーター) を使用して、基本メソッドを呼び出し builder ます。calls the base PrintMembers method with one argument (its builder parameter),
  2. メソッドが PrintMembers true を返した場合は、"," をビルダーに追加します。if the PrintMembers method returned true, append ", " to the builder,
  3. 各レコードの印刷可能なメンバーについて、そのメンバーの名前の後に "=" を追加し、その後にメンバーの値 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 (or this.member.ToString() for value types), separated with ", ",
  4. true を返します。return true.

メソッドは、 PrintMembers 明示的に宣言できます。The PrintMembers method can be declared explicitly. 明示的な宣言が予期されるシグネチャまたはアクセシビリティと一致しない場合、または明示的な宣言で派生型でのオーバーライドが許可されておらず、レコード型がでない場合は、エラーになり 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.

レコードには、次のように宣言されたメソッドに相当する、合成されたメソッドが含まれています。The record includes a synthesized method equivalent to a method declared as follows:

public override string ToString();

メソッドは、明示的に宣言できます。The method can be declared explicitly. 明示的な宣言が予期されるシグネチャまたはアクセシビリティと一致しない場合、または明示的な宣言で派生型でのオーバーライドが許可されておらず、レコード型がでない場合は、エラーになり 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. 合成された、または明示的に宣言されたメソッドがオーバーライドしない場合 object.ToString() (たとえば、中間の基本型のシャドウが原因で)、エラーになります。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.).

合成されたメソッド:The synthesized method:

  1. インスタンスを作成し StringBuilder ます。creates a StringBuilder instance,
  2. レコード名をビルダーに追加し、その後に "{" を追加します。appends the record name to the builder, followed by " { ",
  3. レコードのメソッドを呼び出し PrintMembers てビルダーに渡し、その後に "" が true を返した場合は、invokes the record's PrintMembers method giving it the builder, followed by " " if it returned true,
  4. "}" を追加します。appends "}",
  5. ビルダーの内容をと共に返し builder.ToString() ます。returns the builder's contents with builder.ToString().

たとえば、次のレコードの種類について考えてみます。For example, consider the following record types:

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

これらのレコードの種類では、合成された印刷メンバーは次のようになります。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); 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 void 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

上記のメンバーに加えて、パラメーターリストを持つレコード ("位置指定レコード") は、上記のメンバーと同じ条件を持つ追加のメンバーを合成します。In addition to the above members, records with a parameter list ("positional records") synthesize additional members with the same conditions as the members above.

プライマリコンストラクターPrimary Constructor

レコード型には、型宣言の値パラメーターに対応するシグネチャを持つパブリックコンストラクターがあります。A record type has a public constructor whose signature corresponds to the value parameters of the type declaration. これは、型のプライマリコンストラクターと呼ばれ、暗黙的に宣言された既定のクラスコンストラクター (存在する場合) が抑制されるようにします。This is called the primary constructor for the type, and causes the implicitly declared default class constructor, if present, to be suppressed. プライマリコンストラクターと、同じシグネチャを持つコンストラクターがクラスに既に存在する場合、エラーになります。It is an error to have a primary constructor and a constructor with the same signature already present in the class.

実行時のプライマリコンストラクターAt runtime the primary constructor

  1. クラス本体に出現するインスタンス初期化子を実行しますexecutes the instance initializers appearing in the class-body

  2. 句で指定された引数 record_base (存在する場合) を使用して、基底クラスのコンストラクターを呼び出します。invokes the base class constructor with the arguments provided in the record_base clause, if present

レコードにプライマリコンストラクターがある場合、"コピーコンストラクター" を除くすべてのユーザー定義コンストラクターには、明示的な this コンストラクター初期化子が必要です。If a record has a primary constructor, any user-defined constructor, except "copy constructor" must have an explicit this constructor initializer.

プライマリコンストラクターとレコードのメンバーのパラメーターは、 argument_list 句の内 record_base およびインスタンスフィールドまたはプロパティの初期化子内でスコープ内にあります。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. インスタンスメンバーは、これらの場所ではエラーになります (現在、インスタンスメンバーが通常のコンストラクター初期化子のスコープ内にあるが、使用するエラーが発生します)。ただし、プライマリコンストラクターのパラメーターはスコープ内にあり、シャドウメンバーになります。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. 静的メンバーは、基本呼び出しと初期化子が現在の通常のコンストラクターでどのように動作するかと同様に使用することもできます。Static members would also be useable, similar to how base calls and initializers work in ordinary constructors today.

プライマリコンストラクターのパラメーターが読み取られない場合、警告が生成されます。A warning is produced if a parameter of the primary constructor is not read.

で宣言された式変数 argument_list は、内のスコープ内にあり argument_list ます。Expression variables declared in the argument_list are in scope within the argument_list. 通常のコンストラクター初期化子の引数リスト内にあるものと同じシャドウ規則が適用されます。The same shadowing rules as within an argument list of a regular constructor initializer apply.

プロパティProperties

レコード型宣言の各レコードパラメーターには、対応するパブリックプロパティメンバーがあります。このメンバーの名前と型は、値パラメーターの宣言から取得されます。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.

A レコードの場合:For a record:

  • パブリック get プロパティと init 自動プロパティが作成されます (「個別のアクセサーの指定」を参照してください init )。A public get and init auto-property is created (see separate init accessor specification). abstract一致する型の継承プロパティがオーバーライドされます。An inherited abstract property with matching type is overridden. 継承されたプロパティにオーバーライド可能なアクセサーとアクセサーがない場合、これはエラーになり public get init ます。It is an error if the inherited property does not have public overridable get and init accessors. 自動プロパティは、対応するプライマリコンストラクターパラメーターの値に初期化されます。The auto-property is initialized to the value of the corresponding primary constructor parameter. 属性は、 property: field: 対応するレコードパラメーターに構文的に適用された属性のまたはターゲットを使用して、合成された自動プロパティとそのバッキングフィールドに適用できます。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.

分解Deconstruct

少なくとも1つのパラメーターを持つ位置指定レコード合成は、分解という名前のパブリックな void を返すインスタンスメソッドを使用します。このメソッドは、プライマリコンストラクター宣言の各パラメーターに対して out パラメーター宣言を使用します。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. 分解メソッドの各パラメーターは、プライマリコンストラクター宣言の対応するパラメーターと同じ型を持ちます。Each parameter of the Deconstruct method has the same type as the corresponding parameter of the primary constructor declaration. メソッドの本体は、分解メソッドの各パラメーターを、同じ名前のメンバーに対するインスタンスメンバーアクセスの値に割り当てます。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. メソッドは、明示的に宣言できます。The method can be declared explicitly. 明示的な宣言が、予期されたシグネチャまたはアクセシビリティと一致しない場合、または静的である場合、エラーになります。It is an error if the explicit declaration does not match the expected signature or accessibility, or is static.

withwith expression

with式は、次の構文を使用した新しい式です。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
    ;

with式は、ステートメントとして許可されていません。A with expression is not permitted as a statement.

式では、 with "非破壊的な変異" を許可します。これにより、の割り当てに変更を加えたレシーバー式のコピーが生成され 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.

有効な式には、 with void 以外の型のレシーバーがあります。A valid with expression has a receiver with a non-void type. 受信側の種類はレコードである必要があります。The receiver type must be a record.

式の右側にある with は、 member_initializer_list 識別子 への代入のシーケンスを持つです。これは、受信者の型のアクセス可能なインスタンスフィールドまたはプロパティである必要があります。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.

まず、受信側の "clone" メソッドが呼び出され、その結果が受信側の型に変換されます。First, receiver's "clone" method (specified above) is invoked and its result is converted to the receiver's type. 次に、各 member_initializer は、変換結果のフィールドまたはプロパティへの割り当てと同じ方法で処理されます。Then, each member_initializer is processed the same way as an assignment to a field or property access of the result of the conversion. 割り当ては、構文の順序で処理されます。Assignments are processed in lexical order.