Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Typ struktury (lub typ struktury) to typ wartości, który może hermetyzować dane i powiązane funkcje.
Dokumentacja języka C# zawiera ostatnio wydaną wersję języka C#. Zawiera również początkową dokumentację funkcji w publicznej wersji zapoznawczej nadchodzącej wersji językowej.
Dokumentacja identyfikuje dowolną funkcję po raz pierwszy wprowadzoną w ostatnich trzech wersjach języka lub w bieżącej publicznej wersji zapoznawczej.
Wskazówka
Aby dowiedzieć się, kiedy funkcja została po raz pierwszy wprowadzona w języku C#, zapoznaj się z artykułem dotyczącym historii wersji języka C#.
Użyj słowa kluczowego struct , aby zdefiniować typ struktury:
public struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
public override string ToString() => $"({X}, {Y})";
}
Aby uzyskać informacje o typach ref struct i readonly ref struct, zobacz artykuł Typy struktur ref.
Typy struktur mają semantykę wartości. Oznacza to, że zmienna typu struktury zawiera wystąpienie typu . Domyślnie system kopiuje wartości zmiennych przy przypisaniu, przekazując argument do metody i zwracając wynik metody. W przypadku zmiennych typu struktury system kopiuje wystąpienie typu. Aby uzyskać więcej informacji, zobacz Typy wartości.
Zazwyczaj typy struktur są używane do projektowania małych typów skoncentrowanych na danych, które zapewniają niewielkie lub żadne zachowanie. Na przykład platforma .NET używa typów struktur do reprezentowania liczby (zarówno liczby całkowitej , jak i rzeczywistej), wartości logicznej, znaku Unicode i wystąpienia czasu. Jeśli koncentrujesz się na zachowaniu typu, rozważ zdefiniowanie klasy. Typy klas mają semantykę referencyjną. Oznacza to, że zmienna typu klasy zawiera odwołanie do wystąpienia typu, a nie samego wystąpienia.
Ponieważ typy struktur mają semantyka wartości, zalecamy zdefiniowanie niezmiennych typów struktur.
readonly Struktura
readonly Użyj modyfikatora, aby zadeklarować, że typ struktury jest niezmienny. Wszystkie pola danych struktury readonly muszą być tylko do odczytu.
- Każda deklaracja pola musi mieć modyfikator
readonly. - Każda właściwość, także te automatycznie zaimplementowane, muszą być tylko do odczytu lub
inittylko. Ustawienia dostępne tylko podczas inicjacji są dostępne od wersji 9 języka C#.
Ta reguła gwarantuje, że żaden element członkowski readonly struktury nie modyfikuje stanu struktury. Wszystkie inne elementy członkowskie wystąpienia z wyjątkiem konstruktorów są niejawnie readonly.
Uwaga
readonly W ramach struktury element członkowski danych typu odwołania modyfikowalnego nadal może modyfikować własny stan. Na przykład nie można zastąpić List<T> wystąpienia, ale można do niego dodać nowe elementy.
Poniższy kod definiuje readonly strukturę z ograniczonymi do inicjalizacji ustawieniami właściwości:
public readonly struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; init; }
public double Y { get; init; }
public override string ToString() => $"({X}, {Y})";
}
readonly członkowie instancji
readonly Użyj modyfikatora, aby zadeklarować, że element członkowski wystąpienia nie modyfikuje stanu struktury. Jeśli nie możesz zadeklarować całego typu struktury jako readonly, użyj readonly modyfikatora, aby oznaczyć elementy członkowskie wystąpienia, które nie modyfikują stanu struktury.
W ramach elementu readonly członkowskiego wystąpienia nie można przypisać ich do pól wystąpienia struktury. Jednak członek readonly może wywołać członka, który nie jest readonly. W takim przypadku kompilator tworzy kopię wystąpienia struktury i wywołuje element niebędącyreadonly członkiem tej kopii. W rezultacie pierwotna instancja struktury nie zostaje zmodyfikowana.
Zazwyczaj stosujesz modyfikator readonly do następujących rodzajów elementów członkowskich wystąpienia:
Metody:
public readonly double Sum() { return X + Y; }Modyfikator
readonlymożna również zastosować do metod, które zastępują metody zadeklarowane w System.Object.public readonly override string ToString() => $"({X}, {Y})";Właściwości i indeksatory:
private int counter; public int Counter { readonly get => counter; set => counter = value; }Jeśli musisz zastosować modyfikator
readonlydo obu akcesorów właściwości lub indeksatora, zastosuj go w deklaracji właściwości lub indeksatora.Uwaga
Kompilator deklaruje metodę
getdostępu automatycznie zaimplementowanej właściwości jakoreadonly, niezależnie od obecnościreadonlymodyfikatora w deklaracji właściwości.Modyfikator
readonlymożna zastosować do właściwości lub indeksatora za pomocą akcesorainit.public readonly double X { get; init; }
Modyfikator można zastosować readonly do pól statycznych typu struktury, ale nie do innych statycznych elementów członkowskich, takich jak właściwości lub metody.
Kompilator może korzystać z modyfikatora readonly na potrzeby optymalizacji wydajności. Aby uzyskać więcej informacji, zobacz Unikanie alokacji.
Mutacja nieniszcząca
with Użyj wyrażenia , aby utworzyć kopię wystąpienia typu struktury z zmienionymi określonymi właściwościami i polami. Użyj składni inicjatora obiektów , aby określić, które elementy członkowskie mają być modyfikowane i ich nowe wartości, jak pokazano w poniższym przykładzie:
public readonly struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; init; }
public double Y { get; init; }
public override string ToString() => $"({X}, {Y})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
record Struktura
Można zdefiniować typy struktury rekordów. Typy rekordów zapewniają wbudowane funkcje hermetyzacji danych. Można zdefiniować zarówno typy, jak record struct i readonly record struct . Struktura rekordów nie może być ref struct. Aby uzyskać więcej informacji i przykładów, zobacz Rekordy.
Tablice w linii
Począwszy od języka C# 12, można zadeklarować tablice wbudowane jako struct typ:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
Tablica śródliniowa to struktura zawierająca ciągły blok N elementów tego samego typu. Jest to bezpieczny odpowiednik stałej deklaracji buforu dostępnej tylko w niebezpiecznym kodzie. Tablica śródliniowa ma struct następujące cechy:
- Zawiera jedno pole.
- Struktura nie określa jawnego układu.
Ponadto kompilator weryfikuje System.Runtime.CompilerServices.InlineArrayAttribute atrybut:
- Długość musi być większa niż zero (
> 0). - Typ docelowy musi być strukturą.
W większości przypadków można uzyskać dostęp do tablicy wbudowanej, takiej jak tablica, zarówno do odczytu, jak i zapisu wartości. Można również użyć operatorów zakresu i indeksu .
Istnieją minimalne ograniczenia dotyczące typu poszczególnych elementów pola w tablicy wbudowanej. Nie może to być typ wskaźnika:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
Może to być jednak dowolny typ odwołania lub dowolny typ wartości:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
Tablice wbudowane można używać z niemal dowolną strukturą danych języka C#.
Tablice wbudowane to zaawansowana funkcja języka. Są one przeznaczone dla scenariuszy o wysokiej wydajności, w których wbudowany, ciągły blok elementów jest szybszy niż inne alternatywne struktury danych. Więcej informacji na temat tablic wbudowanych można znaleźć w specyfikacji funkcji.
Inicjalizacja struktur i wartości domyślne
Zmienna struct typu zawiera bezpośrednio dane dla tego structtypu . Ten bezpośredni magazyn danych tworzy rozróżnienie między niezainicjowaną structwartością , która ma wartość domyślną, a zainicjowaną structwartością , która przechowuje wartości ustawione przez utworzenie. Rozważmy na przykład następujący kod:
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
Jak pokazano w poprzednim przykładzie, domyślne wyrażenie wartości ignoruje konstruktor bez parametrów i generuje wartość domyślną typu struktury. Wystąpienie tablicy typu struktury pomija konstruktor bez parametrów i tworzy tablicę wypełnioną wartościami domyślnymi typu struktury.
Najczęstszą sytuacją, w której wartości domyślne są widoczne, jest obecność w tablicach lub innych kolekcjach, gdzie przechowywanie wewnętrzne obejmuje bloki zmiennych. Poniższy przykład tworzy tablicę 30 TemperatureRange struktur, z których każda ma wartość domyślną:
// All elements have default values of 0:
TemperatureRange[] lastMonth = new TemperatureRange[30];
Wszystkie pola składowe struktury muszą być jednoznacznie przypisane podczas tworzenia, ponieważ typy struct przechowują swoje dane bezpośrednio. Wartość default struktury zdecydowanie przypisuje wszystkie pola do wartości 0. Wszystkie pola muszą być zdecydowanie przypisane po wywołaniu konstruktora. Pola można zainicjować przy użyciu następujących mechanizmów:
- Dodaj inicjatory pól do dowolnego pola lub właściwości zaimplementowanej automatycznie.
- Zainicjuj wszystkie pola lub właściwości automatyczne w treści konstruktora.
Jeśli nie zainicjujesz wszystkich pól w strukturę, kompilator dodaje kod do konstruktora, który inicjuje te pola do wartości domyślnej. Struktura przypisana do wartości default jest inicjowana do wzorca 0-bitowego. Struktura zainicjowana przy użyciu new jest inicjowana do wzorca 0-bitowego, a następnie wykonanie dowolnych inicjatorów pól i konstruktora.
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
Każdy struct ma public konstruktor bez parametrów. Jeśli piszesz konstruktor bez parametrów, musi być publiczny. Jeśli struktura deklaruje dowolne inicjatory pól, musi jawnie zadeklarować konstruktor. Ten konstruktor nie musi być bezparametrowy. Jeśli struktura deklaruje inicjatora pól, ale nie konstruktorów, kompilator zgłasza błąd. Każdy jawnie zadeklarowany konstruktor (z parametrami lub bez parametrów) wykonuje wszystkie inicjatory pól dla tej struktury. Wszystkie pola bez inicjatora pola lub przypisania w konstruktorze są ustawione na wartość domyślną. Aby uzyskać więcej informacji, zobacz notatkę dotyczącą propozycji funkcji konstruktorów struktury bez parametrów .
Począwszy od języka C# 12, struct typy mogą definiować podstawowy konstruktor w ramach jego deklaracji. Konstruktory podstawowe zapewniają zwięzłą składnię parametrów konstruktora, które mogą być używane w całej treści struct w dowolnej deklaracji składowej dla tej struktury.
Jeśli wszystkie pola instancji typu struktury są widoczne, możesz również zainicjować je bez operatora new. W takim przypadku należy zainicjować wszystkie pola wystąpienia przed pierwszym użyciem wystąpienia. W poniższym przykładzie pokazano, jak to zrobić:
public static class StructWithoutNew
{
public struct Coords
{
public double x;
public double y;
}
public static void Main()
{
Coords p;
p.x = 3;
p.y = 4;
Console.WriteLine($"({p.x}, {p.y})"); // output: (3, 4)
}
}
Dla wbudowanych typów wartościużyj odpowiednich literałów, aby określić wartość typu.
Ograniczenia dotyczące projektowania typu struktury
Struktury mają większość możliwości typu klasy . Istnieją pewne wyjątki:
- Typ struktury nie może dziedziczyć z innej klasy lub typu struktury i nie może być bazą klasy. Jednak typ struktury może implementować interfejsy.
- Nie można zadeklarować finalizatora w typie struktury.
- Konstruktor typu struktury musi zainicjować wszystkie pola wystąpienia typu.
Przekazywanie zmiennych typu struktury przez referencję
Podczas przekazywania zmiennej typu struktury do metody jako argumentu lub zwracania wartości typu struktury z metody całe wystąpienie typu struktury jest kopiowane. Wartość przekazywana może mieć wpływ na wydajność kodu w scenariuszach o wysokiej wydajności, które obejmują duże typy struktur. Aby uniknąć kopiowania wartości, można przekazać zmienną typu struktura przez referencję. Użyj modyfikatorów parametrów metody ref, out, in lub ref readonly, aby wskazać, że argument musi zostać przekazany przez referencję. Użyj ref returns, aby zwrócić wynik metody według odwołania. Aby uzyskać więcej informacji, zobacz Unikanie alokacji.
ograniczenie struct
struct Użyj słowa kluczowego w ograniczeniustruct, aby określić, że parametr typu jest typem wartości innej niż null. Oba typy struktury i wyliczenia spełniają struct ograniczenie.
Konwersje
W przypadku dowolnego typu struktury (z wyjątkiem ref struct typów) konwersje boksu i rozpasania istnieją do i z System.ValueType typów i System.Object . Konwersje boksu i rozpboxowania istnieją również między typem struktury a dowolnym interfejsem, który implementuje.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz sekcję Struktury specyfikacji języka C#.
Aby uzyskać więcej informacji na temat struct funkcji, zobacz następujące uwagi dotyczące propozycji funkcji:
- Struktury tylko do odczytu
- Członkowskie elementy obiektowe tylko do odczytu
- Konstruktory struktur bez parametrów
-
Zezwalaj na wyrażenie
withw strukturach - struktury rekordów
- Struktury automatycznie domyślne