Sdílet prostřednictvím


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 structa 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 na null. 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