Bagikan melalui


Rekaman (referensi C#)

Anda menggunakan pengubah record untuk menentukan jenis referensi yang menyediakan fungsionalitas bawaan untuk merangkum data. C# 10 mengizinkan sintaks record class sebagai sinonim untuk mengklarifikasi jenis referensi, dan record struct untuk mendefinisikan jenis nilai dengan fungsionalitas serupa.

Saat Anda mendeklarasikan konstruktor utama pada rekaman, pengkompilasi menghasilkan properti publik untuk parameter konstruktor utama. Parameter konstruktor utama ke rekaman disebut sebagai parameter posisional. Pengkompilasi membuat properti posisional yang mencerminkan parameter konstruktor utama atau posisi. Pengkompilasi tidak mensintesis properti untuk parameter konstruktor utama pada jenis yang tidak memiliki record pengubah.

Dua contoh berikut menunjukkan jenis referensi record (atau record class):

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

Dua contoh berikut menunjukkan jenis nilai record struct:

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

Anda juga bisa membuat rekaman dengan properti dan bidang yang dapat diubah:

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

Record structs juga dapat berubah, baik record structs posisional maupun record structs tanpa parameter posisional:

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

Meskipun rekaman dapat berubah, rekaman ini terutama ditujukan untuk mendukung model data yang tidak berubah. Jenis rekaman tersebut menawarkan fitur-fitur berikut:

Contoh sebelumnya memperlihatkan beberapa perbedaan antara rekaman yang merupakan jenis referensi dan rekaman yang merupakan jenis nilai:

  • record atau record class menyatakan jenis referensi. Kata kunci class bersifat opsional, tetapi dapat menambahkan kejelasan bagi pembaca. record struct mendeklarasikan jenis nilai.
  • Properti posisi tidak dapat diubah dalam record class dan readonly record struct. Mereka dapat diubah dalam record struct.

Sisa artikel ini membahas jenis record class dan record struct. Perbedaannya dirinci di setiap bagian. Anda harus memutuskan antara record class dan record struct yang mirip dengan memutuskan antara class dan struct. Istilah rekaman digunakan untuk menjelaskan perilaku yang berlaku untuk semua jenis rekaman. Baik record struct atau record class digunakan untuk menggambarkan perilaku yang hanya berlaku untuk jenis struct atau kelas. Jenis ini record struct diperkenalkan dalam C# 10.

Sintaksis posisi untuk definisi properti

Anda dapat menggunakan parameter posisi untuk mendeklarasikan properti rekaman dan untuk menginisialisasi nilai properti saat Anda membuat instans:

public record Person(string FirstName, string LastName);

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

Saat Anda menggunakan sintaksis posisi untuk definisi properti, pengompilasi akan membuat:

  • Properti pelengkap otomatis publik untuk setiap parameter posisi yang disediakan dalam deklarasi rekaman.
    • Untuk jenis record dan jenis readonly record struct: Properti khusus init.
    • Untuk jenis record struct: Properti baca-tulis.
  • Konstruktor utama yang parameternya cocok dengan parameter posisi pada deklarasi rekaman.
  • Untuk jenis struct rekaman, konstruktor tanpa parameter yang menetapkan setiap bidang ke nilai defaultnya.
  • Metode Deconstruct dengan parameter out untuk setiap parameter posisi disediakan dalam deklarasi rekaman. Metode ini mendekonstruksi properti yang ditentukan dengan menggunakan sintaks posisional; itu mengabaikan properti yang didefinisikan dengan menggunakan sintaks properti standar.

Anda mungkin ingin menambahkan atribut ke salah satu elemen yang dibuat kompiler ini dari definisi rekaman. Anda dapat menambahkan target ke atribut apa pun yang Anda terapkan ke properti rekaman posisi. Contoh berikut menerapkan ke System.Text.Json.Serialization.JsonPropertyNameAttribute setiap properti rekaman Person. Target property: menunjukkan bahwa atribut diterapkan ke properti yang dihasilkan kompiler. Nilai lain adalah field: untuk menerapkan atribut ke bidang, dan param: untuk menerapkan atribut ke parameter.

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

Contoh sebelumnya juga menunjukkan cara membuat komentar dokumentasi XML untuk rekaman. Anda dapat menambahkan tag <param> untuk menambahkan dokumentasi bagi parameter konstruktor utama.

Jika definisi properti autoimplemented yang dihasilkan bukan yang Anda inginkan, Anda dapat menentukan properti Anda sendiri dengan nama yang sama. Misalnya, Anda mungkin ingin mengubah aksesibilitas atau perubahan, atau memberikan implementasi untuk pengakses get atau set. Jika Anda mendeklarasikan properti di sumber, Anda harus menginisialisasinya dari parameter posisi rekaman. Jika properti Anda adalah properti autoimplemented, Anda harus menginisialisasi properti . Jika Anda menambahkan bidang pendukung di sumber, Anda harus menginisialisasi bidang pendukung. Dekonstruktor yang dihasilkan menggunakan definisi properti Anda. Misalnya, contoh berikut mendeklarasikan properti FirstName dan LastName dari rekaman posisi public, tetapi membatasi parameter posisi Id ke internal. Anda dapat menggunakan sintaks ini untuk jenis rekaman dan struct rekaman.

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

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

}

Jenis rekaman tidak harus mendeklarasikan properti posisi apa pun. Anda dapat mendeklarasikan rekaman tanpa properti posisi apa pun, dan Anda dapat mendeklarasikan bidang dan properti lain, seperti dalam contoh berikut:

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

Jika Anda menentukan properti dengan menggunakan sintaks properti standar tetapi menghilangkan pengubah akses, properti private secara implisit.

Ketetapan

Rekaman posisional dan struktur rekaman baca-saja posisi mendeklarasikan properti khusus init. Struct rekaman posisional mendeklarasikan properti baca-tulis. Anda dapat menimpa salah satu default tersebut, seperti yang ditunjukkan di bagian sebelumnya.

Ketetapan dapat berguna ketika Anda memerlukan tipe data-sentris menjadi aman utas atau Anda bergantung pada kode hash yang tetap sama dalam tabel hash. Namun, ketetapan tidak sesuai untuk semua skenario data. Entity Framework Core, misalnya, tidak mendukung pembaruan dengan jenis entitas yang tidak dapat diubah.

Properti khusus init, baik yang dibuat dari parameter posisi (record class, dan readonly record struct) maupun dengan menentukan pengakses init, memiliki ketetapan yang dangkal. Setelah inisialisasi, Anda tidak dapat mengubah nilai properti jenis nilai atau referensi dari properti jenis referensi. Namun, data yang dirujuk properti jenis referensi dapat diubah. Contoh berikut menunjukkan bahwa konten properti tidak berubah tipe referensi (array dalam hal ini) dapat berubah:

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

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

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

Fitur yang unik untuk jenis rekaman diimplementasikan oleh metode yang disintesis kompiler, dan tidak ada satu pun dari metode tersebut yang berkompromi terhadap ketetapan dengan memodifikasi status objek. Kecuali ditentukan, metode yang disintesis dihasilkan untuk deklarasi record, record struct, dan readonly record struct.

Kesetaraan nilai

Jika Anda tidak mengambil alih atau mengganti metode kesetaraan, jenis yang Anda nyatakan mengatur bagaimana kesetaraan ditentukan:

  • Untuk jenis class, dua objek sama jika merujuk ke objek yang sama dalam memori.
  • Untuk jenis struct, dua objek sama jika memiliki jenis yang sama dan menyimpan nilai yang sama.
  • Untuk jenis dengan pengubah record (record class, record struct, dan readonly record struct), dua objek sama jika memiliki jenis yang sama dan menyimpan nilai yang sama.

Definisi kesetaraan untuk record struct sama dengan untuk struct. Perbedaannya adalah bahwa untuk struct, implementasi berada di ValueType.Equals(Object) dan bergantung pada refleksi. Untuk rekaman, implementasinya disintesis kompiler dan menggunakan anggota data yang dideklarasikan.

Kesetaraan referensi diperlukan untuk beberapa model data. Misalnya, Entity Framework Core bergantung pada kesamaan referensi untuk memastikan bahwa Entity Framework Core hanya menggunakan satu instans dari jenis entitas untuk apa yang secara konseptual merupakan satu entitas. Untuk alasan ini, rekaman dan struct rekaman tidak sesuai digunakan sebagai jenis entitas di Entity Framework Core.

Contoh berikut mengilustrasikan kesetaraan nilai jenis rekaman:

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

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

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

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

Untuk mengimplementasikan kesetaraan nilai, kompilator mensintesis beberapa metode, termasuk:

  • Penimpaan dari Object.Equals(Object). Ini adalah kesalahan jika penimpaan dinyatakan secara eksplisit.

    Metode ini digunakan sebagai dasar untuk metode statis Object.Equals(Object, Object) ketika kedua parameter non-null.

  • , virtualatau sealed, Equals(R? other) di mana R adalah jenis catatan. Metode ini mengimplementasikan IEquatable<T>. Metode ini dapat dinyatakan secara eksplisit.

  • Jika jenis catatan berasal dari jenis Basecatatan dasar , Equals(Base? other). Ini adalah kesalahan jika penimpaan dinyatakan secara eksplisit. Jika Anda memberikan implementasi Anda sendiri dari Equals(R? other), berikan implementasi GetHashCode juga.

  • Penimpaan dari Object.GetHashCode(). Metode ini dapat dinyatakan secara eksplisit.

  • Menimpa operator == dan !=. Ini adalah kesalahan jika operator dinyatakan secara eksplisit.

  • Jika jenis rekaman berasal dari jenis catatan dasar, protected override Type EqualityContract { get; };. Properti ini dapat dinyatakan secara eksplisit. Untuk informasi selengkapnya, lihat Kesetaraan dalam hierarki pewarisan.

Pengkompilasi tidak mensintesis metode ketika jenis rekaman memiliki metode yang cocok dengan tanda tangan metode yang disintesis yang diizinkan untuk dideklarasikan secara eksplisit.

Mutasi tidak merusak

Jika Anda perlu menyalin instans dengan beberapa modifikasi, Anda dapat menggunakan ekspresi with untuk mencapai mutasi yang tidak merusak. Ekspresi with membuat instans rekaman baru yang merupakan salinan dari instans rekaman yang sudah ada, dengan properti dan bidang tertentu yang dimodifikasi. Anda menggunakan sintaks penginisialisasi objek untuk menentukan nilai yang akan diubah, seperti yang diperlihatkan dalam contoh berikut:

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

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

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

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

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

Ekspresi with dapat mengatur properti posisi atau properti yang dibuat dengan menggunakan sintaks properti standar. Properti yang dideklarasikan secara eksplisit harus memiliki init aksesor atau set untuk diubah dalam with ekspresi.

Hasil dari ekspresi with adalah salinan dangkal, yang berarti bahwa untuk properti referensi, hanya referensi ke instans yang disalin. Baik rekaman asli maupun salinan berakhir dengan referensi ke instans yang sama.

Untuk mengimplementasikan fitur ini untuk jenis record class, kompiler mensintesis metode kloning dan konstruktor salinan. Metode kloning virtual menghasilkan rekaman baru yang diinisialisasi oleh konstruktor salinan. Saat Anda menggunakan ekspresi with, kompiler membuat kode yang memanggil metode kloning lalu mengatur properti yang ditentukan dalam ekspresi with.

Jika Anda memerlukan perilaku penyalinan yang berbeda, Anda dapat menulis konstruktor salinan Anda sendiri di record class. Jika Anda melakukan itu, pengkompilasi tidak mensintesis satu. Buat konstruktor private jika rekaman adalah sealed, jika tidak, buatlah protected. Kompiler tidak mensintesis konstruktor salinan untuk jenisrecord struct. Anda dapat menulisnya, tetapi pengkompilasi tidak menghasilkan panggilan untuk with ekspresi. Nilai record struct disalin pada penugasan.

Anda tidak dapat menimpa metode kloning, dan Anda tidak dapat membuat anggota bernama Clone dalam jenis rekaman apa pun. Nama aktual dari metode kloning dihasilkan kompiler.

Pemformatan bawaan untuk ditampilkan

Jenis rekaman memiliki metode ToString yang dihasilkan kompiler yang menampilkan nama dan nilai properti serta bidang publik. Metode ToString mengembalikan string dari format berikut:

<nama jenis rekaman> { <property name> = <value>, <property name> = <value>, ...}

String yang dicetak untuk <value> adalah string yang dikembalikan oleh ToString() untuk jenis properti. Dalam contoh berikut, ChildNames adalah System.Array, di mana ToString mengembalikan System.String[]:

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

Untuk mengimplementasikan fitur ini, dalam jenis record class, Kompiler mensintesis metode virtual PrintMembers dan menimpa ToString. Dalam jenis record struct, anggota ini adalah private. Penimpaan ToString membuat objek StringBuilder dengan nama jenis diikuti dengan tanda kurung buka. Ini memanggil PrintMembers untuk menambahkan nama dan nilai properti, lalu menambahkan tanda kurung tutup. Contoh berikut menunjukkan kode yang mirip dengan apa yang dikandung oleh penimpaan yang disintesis:

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

Anda dapat memberikan implementasi PrintMembers milik Anda sendiri atau penimpaan ToString. Contoh disediakan dalam pemformatan PrintMembers di bagian rekaman turunan nanti di artikel ini. Dalam C# 10 dan yang lebih baru, implementasi ToString dapat mencakup pengubah sealed, yang mencegah kompiler mensintesis implementasi ToString untuk setiap rekaman turunan. Anda dapat membuat representasi string yang konsisten di seluruh hierarki jenis record . (Rekaman turunan masih memiliki metode yang PrintMembers dihasilkan untuk semua properti turunan.)

Warisan

Bagian ini hanya berlaku pada jenis record class.

Rekaman dapat mewariskan dari rekaman lain. Namun, catatan tidak dapat menerima warisan dari kelas, dan kelas tidak dapat menerima warisan dari catatan.

Parameter posisi dalam jenis rekaman turunan

Rekaman turunan mendeklarasikan parameter posisional untuk semua parameter di konstruktor utama rekaman dasar. Rekaman dasar mendeklarasikan dan menginisialisasi properti tersebut. Rekaman turunan tidak menyembunyikan properti tersebut, tapi hanya membuat dan menginisialisasi properti untuk parameter yang tidak dideklarasikan dalam rekaman dasarnya.

Contoh berikut mengilustrasikan pewarisan dengan sintaksis properti posisi:

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

Kesetaraan dalam hierarki warisan

Bagian ini berlaku untuk jenis record class, tetapi bukan jenis record struct. Agar dua variabel rekaman sama, jenis runtime harus sama. Jenis variabel yang menampung dapat berbeda. Perbandingan kesetaraan yang diwariskan diilustrasikan dalam contoh kode berikut:

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

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

Dalam contoh, semua variabel dinyatakan sebagai Person, bahkan ketika instans adalah jenis turunan baik dari Student maupun Teacher. Instans memiliki properti yang sama dan nilai properti yang sama. Tetapi student == teacher mengembalikan False meskipun keduanya adalah Personvariabel -jenis, dan student == student2 mengembalikan True meskipun satu adalah variabel Person dan satu adalah variabel Student. Uji kesetaraan tergantung pada jenis runtime objek yang sebenarnya, bukan jenis variabel yang dideklarasikan.

Untuk mengimplementasikan perilaku ini, kompiler mensintesis properti EqualityContract yang mengembalikan objek Type yang cocok dengan jenis rekaman. EqualityContract memungkinkan metode kesetaraan untuk membandingkan jenis runtime objek saat mereka memeriksa kesetaraan. Jika jenis dasar rekaman adalah object, properti ini adalah virtual. Jika jenis dasar adalah jenis rekaman lain, properti ini adalah penimpaan. Jika jenis rekaman adalah sealed, properti ini secara efektif sealed karena jenisnya adalah sealed.

Ketika kode membandingkan dua instans dari jenis turunan, metode kesetaraan yang disintesis memeriksa semua anggota data dari jenis dasar dan turunan untuk kesetaraan. Metode yang disintesis GetHashCodeGetHashCode menggunakan metode dari semua anggota data yang dideklarasikan dalam jenis dasar dan jenis catatan turunan. Anggota data dari record mencakup semua bidang yang dideklarasikan dan bidang backing yang disintesis kompilator untuk properti yang diimplementasikan secara otomatis.

ekspresi with dalam rekaman turunan

Hasil ekspresi with memiliki jenis run-time yang sama dengan operand ekspresi. Semua properti jenis run-time disalin, tetapi Anda hanya dapat mengatur properti jenis waktu kompilasi, seperti yang ditunjukkan contoh berikut:

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

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

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

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

pemformatan PrintMembers dalam rekaman turunan

Metode PrintMembers yang disintesis dari jenis rekaman turunan memanggil implementasi dasar. Hasilnya adalah bahwa semua properti publik dan bidang dari kedua jenis turunan dan dasar termasuk dalam output ToString, seperti yang ditunjukkan dalam contoh berikut:

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

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

Anda dapat memberikan implementasi dari metode PrintMembers milik Anda sendiri. Jika Anda melakukannya, gunakan tanda tangan berikut:

  • Untuk rekaman sealed yang berasal dari object (tidak mendeklarasikan rekaman dasar): private bool PrintMembers(StringBuilder builder);
  • Untuk rekaman sealed yang berasal dari rekaman lain (perhatikan bahwa jenis penutup adalah sealed, sehingga metode ini efektif sealed): protected override bool PrintMembers(StringBuilder builder);
  • Untuk rekaman yang bukan sealed dan berasal dari objek: protected virtual bool PrintMembers(StringBuilder builder);
  • Untuk rekaman yang bukan sealed dan berasal dari rekaman lain: protected override bool PrintMembers(StringBuilder builder);

Berikut adalah contoh kode yang menggantikan metode PrintMembers yang disintesis, satu untuk jenis rekaman yang berasal dari objek, dan satu untuk jenis rekaman yang berasal dari rekaman lain:

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

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

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

Catatan

Dalam C# 10 dan yang lebih baru, kompiler akan mensintesis PrintMembers dalam rekaman turunan bahkan ketika rekaman dasar telah menyegel metode ToString. Anda juga dapat membuat implementasi Anda sendiri dari PrintMembers.

Perilaku dekonstruktor dalam rekaman turunan

Metode Deconstruct rekaman turunan mengembalikan nilai semua properti posisi dari jenis waktu kompilasi. Jika tipe variabel adalah rekaman dasar, hanya properti rekaman dasar yang didekonstruksi kecuali objek dilemparkan ke tipe turunan. Contoh berikut menunjukkan pemanggilan dekonstruktor pada rekaman turunan.

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

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

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

Batasan generik

Kata record kunci adalah pengubah untuk class jenis atau struct . Menambahkan pengubah record menyertakan perilaku yang dijelaskan sebelumnya dalam artikel ini. Tidak ada batasan generik yang mengharuskan jenis menjadi rekaman. Memenuhi record class batasan class . Memenuhi record struct batasan struct . Untuk informasi selengkapnya, lihat Batasan pada Parameter Jenis.

Spesifikasi bahasa C#

Untuk informasi selengkapnya, lihat bagian Kelas dari Spesifikasi bahasa C#.

Untuk informasi selengkapnya tentang fitur-fitur ini, lihat catatan proposal fitur berikut ini:

Lihat juga