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:
- Sintaksis ringkas untuk membuat jenis referensi dengan properti yang tidak dapat diubah
- Perilaku bawaan berguna untuk jenis referensi yang ber sentris data:
- Dukungan untuk hierarki pewarisan
Contoh sebelumnya memperlihatkan beberapa perbedaan antara rekaman yang merupakan jenis referensi dan rekaman yang merupakan jenis nilai:
record
ataurecord class
menyatakan jenis referensi. Kata kunciclass
bersifat opsional, tetapi dapat menambahkan kejelasan bagi pembaca.record struct
mendeklarasikan jenis nilai.- Properti posisi tidak dapat diubah dalam
record class
danreadonly record struct
. Mereka dapat diubah dalamrecord 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 jenisreadonly record struct
: Properti khusus init. - Untuk jenis
record struct
: Properti baca-tulis.
- Untuk jenis
- 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 parameterout
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
, danreadonly 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.
,
virtual
atausealed
,Equals(R? other)
di manaR
adalah jenis catatan. Metode ini mengimplementasikan IEquatable<T>. Metode ini dapat dinyatakan secara eksplisit.Jika jenis catatan berasal dari jenis
Base
catatan dasar ,Equals(Base? other)
. Ini adalah kesalahan jika penimpaan dinyatakan secara eksplisit. Jika Anda memberikan implementasi Anda sendiri dariEquals(R? other)
, berikan implementasiGetHashCode
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 Person
variabel -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 GetHashCode
GetHashCode
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 dariobject
(tidak mendeklarasikan rekaman dasar):private bool PrintMembers(StringBuilder builder)
; - Untuk rekaman
sealed
yang berasal dari rekaman lain (perhatikan bahwa jenis penutup adalahsealed
, sehingga metode ini efektifsealed
):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
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk