Konstruktory struktury bez parametrů
Poznámka
Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.
Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v příslušných poznámkáchze schůzky návrhu jazyka (LDM)
Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .
Shrnutí
Podpora konstruktorů bez parametrů a inicializátorů polí instance pro typy struktur.
Motivace
Explicitní konstruktory bez parametrů by poskytovaly větší kontrolu nad minimálními vytvořenými instancemi typu struktury.
Inicializátory polí instance umožňují zjednodušenou inicializaci napříč více konstruktory.
Společně by se tím zavřela jasná mezera mezi deklaracemi struct
a class
.
Podpora inicializátorů polí by také umožňovala inicializaci polí v deklaracích record struct
bez explicitní implementace primárního konstruktoru.
record struct Person(string Name)
{
public object Id { get; init; } = GetNextId();
}
Pokud jsou inicializátory polí struktury podporovány pro konstruktory s parametry, zdá se přirozené rozšířit i na konstruktory bez parametrů.
record struct Person()
{
public string Name { get; init; }
public object Id { get; init; } = GetNextId();
}
Návrh
Inicializátory polí instance
Deklarace polí instance pro strukturu mohou zahrnovat inicializátory.
Stejně jako u inicializátorů pole třídy §15.5.6.3:
Inicializátor proměnné pro pole instance nemůže odkazovat na instanci, která se vytváří.
Objeví se chyba, pokud má struktura inicializátory polí a žádné deklarované konstruktory instance, protože inicializátory polí nebudou spuštěny.
struct S { int F = 42; } // error: 'struct' with field initializers must include an explicitly declared constructor
Konstruktory
Struktura může deklarovat konstruktor instance bez parametrů.
Konstruktor instance bez parametrů je platný pro všechny druhy struktur, včetně struct
, readonly struct
, ref struct
a record struct
.
Pokud není deklarován žádný konstruktor instance bez parametrů, struktura (viz §16.4.9) ...
implicitně má konstruktor instance bez parametrů, který vždy vrací hodnotu, která je výsledkem nastavení všech polí typu hodnoty na výchozí hodnotu a všechna pole typu odkazu na hodnotu null.
Modifikátory
Konstruktor instance struktury bez parametrů musí být deklarován public
.
struct S0 { } // ok
struct S1 { public S1() { } } // ok
struct S2 { internal S2() { } } // error: parameterless constructor must be 'public'
Neveřejné konstruktory se při importu typů z metadat ignorují.
Konstruktory lze deklarovat extern
nebo unsafe
.
Konstruktory nemohou být partial
.
Provádění inicializátorů polí
Inicializátory proměnných instance (§15.11.3) jsou změněny následujícím způsobem:
Pokud třídy konstruktor instance nemá žádný konstruktor inicializátor nebo má konstruktor inicializátor formuláře
base(...)
, tento konstruktor implicitně provádí inicializace určené variable_initializers polí instance deklarovaných ve své třídě. To odpovídá posloupnosti přiřazení, která jsou provedena okamžitě po vstupu do konstruktoru a před implicitním vyvoláním přímého konstruktoru základní třídy.Pokud konstruktor instance struktury nemá žádný inicializátor konstruktoru, tento konstruktor implicitně provádí inicializace určené variable_initializers polí instance deklarovaných v jeho struktuře. Představuje posloupnost přiřazení, která se vykonávají okamžitě při vstupu do konstruktoru.
Pokud konstruktor instance struktury má
this()
konstruktor inicializátor, který představuje výchozí konstruktor bez parametrů, deklarovaný konstruktor implicitně vymaže všechna pole instance a provede inicializace zadané variable_initializers polí instance deklarovaných ve své struktuře. Okamžitě po zadání do konstruktoru jsou všechna pole typu hodnoty nastavena na výchozí hodnotu a všechna pole typu odkazu jsou nastavena nanull
. Ihned poté se provede posloupnost přiřazení odpovídající inicializátorům proměnných .
Určité přiřazení
Pole instance (kromě polí fixed
) musí být rozhodně přiřazena v konstruktorech instancí struktury, které nemají inicializátor this()
(viz §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; }
}
Bez inicializátoru base()
Inicializátor base()
je zakázán ve strukturových konstruktorech.
Kompilátor nevygeneruje volání na základní konstruktor System.ValueType
z konstruktorů instance struktury.
record struct
Je hlášena chyba, pokud record struct
obsahuje inicializátory polí a neobsahuje primární konstruktor ani žádné konstruktory instance, protože inicializátory polí nebudou spuštěny.
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
se seznamem prázdných parametrů bude mít primární konstruktor bez parametrů.
record struct R3(); // primary .ctor: public R3() { }
record struct R4() { int F = 42; } // primary .ctor: public R4() { F = 42; }
Explicitní konstruktor bez parametrů v record struct
musí mít this
inicializátor, který volá primární konstruktor nebo explicitně deklarovaný konstruktor.
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;
}
Pole
Implicitně definovaný konstruktor bez parametrů nastaví pole na nulu, místo aby volal jakékoliv konstruktory bez parametrů pro typy polí. Nejsou hlášena žádná upozornění, že konstruktory polí jsou ignorovány. Žádná změna oproti 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
}
výraz default
default
ignoruje konstruktor bez parametrů a vygeneruje nulovou instanci.
Žádná změna oproti C#9.
// struct S { public S() { } }
_ = default(S); // constructor ignored, no warning
new()
Vytvoření objektu vyvolá konstruktor bez parametrů, pokud je veřejný; v opačném případě je instance nulová. Žádná změna oproti C#9.
// public struct PublicConstructor { public PublicConstructor() { } }
// public struct PrivateConstructor { private PrivateConstructor() { } }
_ = new PublicConstructor(); // call PublicConstructor::.ctor()
_ = new PrivateConstructor(); // initobj PrivateConstructor
Varování může vydávat upozornění na použití new()
s typem struktury, který obsahuje konstruktory, ale nemá beparametrový konstruktor.
Při náhradě parametru typu takovým typem struktury, který má omezení new()
nebo struct
, se nezobrazí žádné upozornění.
struct S { public S(int i) { } }
static T CreateNew<T>() where T : new() => new T();
_ = new S(); // no warning called
_ = CreateNew<S>(); // ok
Neinicializované hodnoty
Místní proměnná nebo pole typu struktury, které není explicitně inicializováno, je nulové. Kompilátor hlásí konkrétní chybu přiřazení pro neinicializovanou strukturu, která není prázdná. Žádná změna oproti 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)
Přidělení pole
Při alokaci pole se ignoruje jakýkoli konstruktor bez parametrů a vygenerují prvky s nulovými hodnotami. Žádná změna od C#9.
// struct S { public S() { } }
var a = new S[1]; // constructor ignored, no warning
Výchozí hodnota parametru new()
Výchozí hodnota parametru new()
vytvoří vazbu na konstruktor bez parametrů, pokud je veřejný (a hlásí chybu, že hodnota není konstantní); v opačném případě je instance nulová.
Žádná změna z 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
Omezení parametrů typu: new()
a struct
Omezení parametrů typu new()
a struct
vyžadují, aby konstruktor bez parametrů byl public
(viz vyhovující omezení - §8.4.5).
Kompilátor předpokládá, že všechny struktury splňují new()
a struct
omezení.
Žádná změna oproti 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()
je vyslán jako volání na System.Activator.CreateInstance<T>()
a kompilátor předpokládá, že implementace CreateInstance<T>()
vyvolá konstruktor public
bez parametrů, pokud je definován.
Pomocí rozhraní .NET Framework Activator.CreateInstance<T>()
vyvolá konstruktor bez parametrů, pokud je omezení where T : new()
ale zdá se ignorovat konstruktor bez parametrů, pokud je omezení where T : struct
.
Volitelné parametry
Konstruktory s volitelnými parametry se nepovažují za konstruktory bez parametrů. Žádná změna oproti 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
Explicitní konstruktory instancí struktur bez parametrů budou vygenerovány do metadat.
Veřejné konstruktory instance bez parametrů budou importovány z metadat; konstruktory instance nepřístupné struktury budou ignorovány. Žádná změna oproti C#9.
Viz také
Schůzky o návrhu
- 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