Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Nota
Artikel ini adalah spesifikasi fitur. Spesifikasi berfungsi sebagai dokumen desain untuk fitur tersebut. Ini termasuk perubahan spesifikasi yang diusulkan, bersama dengan informasi yang diperlukan selama desain dan pengembangan fitur. Artikel ini diterbitkan sampai perubahan spesifikasi yang diusulkan diselesaikan dan dimasukkan dalam spesifikasi ECMA saat ini.
Mungkin ada beberapa perbedaan antara spesifikasi fitur dan implementasi yang selesai. Perbedaan tersebut tercakup dalam catatan rapat desain bahasa terkait (LDM) .
Anda dapat mempelajari lebih lanjut tentang proses untuk mengadopsi speklet fitur ke dalam standar bahasa C# dalam artikel tentang spesifikasi .
Isu juara: https://github.com/dotnet/csharplang/issues/99
Ringkasan
Mendukung konstruktor tanpa parameter dan penginisialisasi bidang instans untuk jenis struct.
Motivasi
Konstruktor tanpa parameter eksplisit akan memberikan kontrol lebih besar atas instans jenis struct yang dibuat secara minimal.
Penginisialisasi bidang instans akan memungkinkan inisialisasi yang disederhanakan di beberapa konstruktor.
Bersama-sama ini akan menutup kesenjangan yang jelas antara deklarasi struct
dan class
.
Dukungan untuk penginisialisasi bidang juga akan memungkinkan inisialisasi bidang dalam deklarasi record struct
tanpa menerapkan konstruktor utama secara eksplisit.
record struct Person(string Name)
{
public object Id { get; init; } = GetNextId();
}
Jika penginisialisasi bidang struktur didukung untuk konstruktor dengan parameter, tampaknya wajar untuk memperluasnya ke konstruktor tanpa parameter juga.
record struct Person()
{
public string Name { get; init; }
public object Id { get; init; } = GetNextId();
}
Usulan
Penginisialisasi bidang instance
Deklarasi bidang instans untuk struktur dapat mencakup penginisialisasi.
Seperti halnya penginisialisasi bidang kelas §15.5.6.3:
Penginisialisasi variabel untuk bidang instans tidak dapat mereferensikan instans yang sedang dibuat.
Kesalahan dilaporkan jika struct memiliki penginisialisasi bidang dan tidak ada konstruktor instans yang dideklarasikan karena penginisialisasi bidang tidak akan dijalankan.
struct S { int F = 42; } // error: 'struct' with field initializers must include an explicitly declared constructor
Konstruktor
Struct dapat mendeklarasikan konstruktor instans tanpa parameter.
Konstruktor instans tanpa parameter valid untuk semua jenis struct termasuk struct
, readonly struct
, ref struct
, dan record struct
.
Jika tidak ada konstruktor instans tanpa parameter yang dideklarasikan, struktur (lihat §16.4.9) ...
secara implisit memiliki konstruktor instans tanpa parameter yang selalu mengembalikan nilai yang dihasilkan dari pengaturan semua bidang jenis nilai ke nilai defaultnya dan semua bidang jenis referensi ke null.
Pengubah
Konstruktor struct instans tanpa parameter harus dinyatakan public
.
struct S0 { } // ok
struct S1 { public S1() { } } // ok
struct S2 { internal S2() { } } // error: parameterless constructor must be 'public'
Konstruktor non-publik diabaikan saat mengimpor jenis dari metadata.
Konstruktor dapat dideklarasikan extern
atau unsafe
.
Konstruktor tidak boleh partial
.
Mengeksekusi penginisialisasi bidang
Inisialisasi variabel instans (§15.11.3) dimodifikasi sebagai berikut:
Ketika konstruktor dari instans kelas tidak memiliki penginisialisasi konstruktor, atau memiliki penginisialisasi konstruktor berbentuk
base(...)
, konstruktor tersebut secara implisit melaksanakan inisialisasi yang ditentukan oleh variable_initializerdari bidang-bidang instans yang dideklarasikan di dalam kelasnya. Ini sesuai dengan urutan penugasan yang dijalankan segera setelah masuk ke konstruktor dan sebelum pemanggilan implisit konstruktor kelas dasar langsung.Ketika konstruktor instans struct tidak memiliki inisialisasi konstruktor, konstruktor tersebut secara implisit melakukan inisialisasi yang ditentukan oleh variable_initializerdari bidang instans yang dideklarasikan dalam strukturnya. Ini sesuai dengan rangkaian penugasan yang dilaksanakan segera setelah masuk ke konstruktor.
Ketika konstruktor instans struct memiliki penginisialisasi konstruktor
this()
yang mewakili konstruktor tanpa parameter default, konstruktor yang dinyatakan secara implisit menghapus semua bidang instans dan melakukan inisialisasi yang ditentukan oleh variable_initializerdari bidang instans yang dideklarasikan dalam strukturnya. Segera setelah masuk ke konstruktor, semua bidang jenis nilai diatur ke nilai defaultnya dan semua bidang jenis referensi diatur kenull
. Segera setelah itu, serangkaian penugasan yang berkorespondensi dengan variable_initializerdijalankan.
Penugasan pasti
Bidang instans (selain bidang fixed
) harus ditentukan dengan pasti dalam konstruktor instans struct yang tidak memiliki penginisialisasi this()
(lihat §16.4.9).
struct S0 // ok
{
int x;
object y;
}
struct S1 // error: 'struct' with field initializers must include an explicitly declared constructor
{
int x = 1;
object y;
}
struct S2
{
int x = 1;
object y;
public S2() { } // error in C# 10 (valid starting in C# 11): field 'y' must be assigned
}
struct S3 // ok
{
int x = 1;
object y;
public S3() { y = 2; }
}
Tidak ada penginisialisasi base()
Penginisialisasi base()
tidak diperbolehkan dalam konstruktor struct.
Kompilator tidak akan menghasilkan panggilan ke konstruktor System.ValueType
dasar dari konstruktor instance struct.
record struct
Kesalahan dilaporkan jika record struct
memiliki penginisialisasi bidang dan tidak berisi konstruktor utama atau konstruktor instans apa pun karena penginisialisasi bidang tidak akan dijalankan.
record struct R0; // ok
record struct R1 { int F = 42; } // error: 'struct' with field initializers must include an explicitly declared constructor
record struct R2() { int F = 42; } // ok
record struct R3(int F); // ok
record struct
dengan daftar parameter kosong akan memiliki konstruktor utama tanpa parameter.
record struct R3(); // primary .ctor: public R3() { }
record struct R4() { int F = 42; } // primary .ctor: public R4() { F = 42; }
Konstruktor tanpa parameter eksplisit dalam record struct
harus memiliki penginisialisasi this
yang memanggil konstruktor utama atau konstruktor yang dinyatakan secara eksplisit.
record struct R5(int F)
{
public R5() { } // error: must have 'this' initializer that calls explicit .ctor
public R5(object o) : this() { } // ok
public int F = F;
}
Bidang
Konstruktor parameterless yang ditentukan secara implisit akan mengosongkan bidang-bidang alih-alih memanggil konstruktor tanpa parameter untuk jenis bidang. Tidak dilaporkan adanya peringatan bahwa konstruktor bidang diabaikan. Tidak ada perubahan dari C#9.
struct S0
{
public S0() { }
}
struct S1
{
S0 F; // S0 constructor ignored
}
struct S<T> where T : struct
{
T F; // constructor (if any) ignored
}
ekspresi default
default
mengabaikan konstruktor tanpa parameter dan menghasilkan instans nol.
Tidak ada perubahan dari C#9.
// struct S { public S() { } }
_ = default(S); // constructor ignored, no warning
new()
Pembuatan objek memanggil konstruktor tanpa parameter jika publik; jika tidak, instans dinilai nol. Tidak ada perubahan dari C#9.
// public struct PublicConstructor { public PublicConstructor() { } }
// public struct PrivateConstructor { private PrivateConstructor() { } }
_ = new PublicConstructor(); // call PublicConstructor::.ctor()
_ = new PrivateConstructor(); // initobj PrivateConstructor
Gelombang peringatan dapat melaporkan peringatan untuk penggunaan new()
dengan jenis struct yang memiliki konstruktor tetapi tidak ada konstruktor tanpa parameter.
Tidak ada peringatan yang akan dilaporkan saat menggunakan penggantian jenis struct tersebut untuk parameter jenis dengan batasan new()
atau struct
.
struct S { public S(int i) { } }
static T CreateNew<T>() where T : new() => new T();
_ = new S(); // no warning called
_ = CreateNew<S>(); // ok
Nilai yang tidak diinisialisasi
Lokal atau bidang jenis struct yang tidak diinisialisasi secara eksplisit adalah nol. Pengkompilasi melaporkan kesalahan penetapan pasti untuk struct yang tidak diinisialisasi yang tidak kosong. Tidak ada perubahan dari C#9.
NoConstructor s1;
PublicConstructor s2;
s1.ToString(); // error: use of unassigned local (unless type is empty)
s2.ToString(); // error: use of unassigned local (unless type is empty)
Pengalokasian array
Alokasi array mengabaikan konstruktor tanpa parameter dan menghasilkan elemen nol. Tidak ada perubahan dari C#9.
// struct S { public S() { } }
var a = new S[1]; // constructor ignored, no warning
Nilai default parameter new()
Nilai default parameter new()
mengikat konstruktor tanpa parameter jika publik (dan melaporkan kesalahan bahwa nilainya tidak konstan); jika tidak, instans dinilai nol.
Tidak ada perubahan dari C#9.
// public struct PublicConstructor { public PublicConstructor() { } }
// public struct PrivateConstructor { private PrivateConstructor() { } }
static void F1(PublicConstructor s1 = new()) { } // error: default value must be constant
static void F2(PrivateConstructor s2 = new()) { } // ok: initobj
Batasan parameter jenis: new()
dan struct
Batasan parameter jenis new()
dan struct
mengharuskan konstruktor tanpa parameter public
jika ditentukan (lihat Memenuhi batasan - §8.4.5).
Pengkompilasi mengasumsikan semua struktur memenuhi batasan new()
dan struct
.
Tidak ada perubahan dari C#9.
// public struct PublicConstructor { public PublicConstructor() { } }
// public struct InternalConstructor { internal InternalConstructor() { } }
static T CreateNew<T>() where T : new() => new T();
static T CreateStruct<T>() where T : struct => new T();
_ = CreateNew<PublicConstructor>(); // ok
_ = CreateStruct<PublicConstructor>(); // ok
_ = CreateNew<InternalConstructor>(); // compiles; may fail at runtime
_ = CreateStruct<InternalConstructor>(); // compiles; may fail at runtime
new T()
dipancarkan sebagai panggilan ke System.Activator.CreateInstance<T>()
, dan kompilator mengasumsikan implementasi CreateInstance<T>()
memanggil konstruktor tanpa parameter public
jika ditentukan.
Dengan .NET Framework, Activator.CreateInstance<T>()
memanggil konstruktor tanpa parameter jika batasan where T : new()
tetapi tampaknya mengabaikan konstruktor tanpa parameter jika batasannya where T : struct
.
Parameter opsional
Konstruktor dengan parameter opsional tidak dianggap sebagai konstruktor tanpa parameter. Tidak ada perubahan dari C#9.
struct S1 { public S1(string s = "") { } }
struct S2 { public S2(params object[] args) { } }
_ = new S1(); // ok: ignores constructor
_ = new S2(); // ok: ignores constructor
Metadata
Konstruktor instans struct tanpa parameter eksplisit akan dipancarkan ke metadata.
Konstruktor instans struct tanpa parameter publik akan diimpor dari metadata; konstruktor instans struct non-publik akan diabaikan. Tidak ada perubahan dari C#9.
Lihat juga
Rapat desain
- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-28.md#open-questions-in-record-and-parameterless-structs
- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-10.md#parameterless-struct-constructors
- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-01-27.md#field-initializers
C# feature specifications