Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Sie können verschiedene Operatoren und Ausdrücke zum Zugriff auf einen Typmember verwenden. Memberzugriffsoperatoren umfassen Memberzugriff (.), Zugriff auf Arrayelemente oder Indexer ([]), Index-vom-Ende (^), Bereich (..), null-bedingte Operatoren (?. und ?[]) und Methodenaufruf (()). Zu diesen Operatoren gehören der null-bedingte Memberzugriff () und der Indexerzugriff (?.).
-
.(Memberzugriff): Zugreifen auf ein Mitglied eines Namespaces oder eines Typs. -
[](Arrayelement oder Indexerzugriff): Greifen Sie auf ein Arrayelement oder einen Typindexer zu. -
?.und?[](Null-bedingte Operatoren): Führen Sie einen Member- oder Elementzugriffsvorgang nur aus, wenn ein Operand ungleich NULL ist. -
()(Aufruf): Rufen Sie eine Methode auf, auf die zugegriffen wird, oder rufen Sie einen Delegaten auf. -
^(Index von Ende): Gibt an, dass die Elementposition vom Ende einer Sequenz stammt. -
..(Range): Geben Sie einen Indizesbereich an, den Sie verwenden können, um einen Bereich von Sequenzelementen abzurufen.
Die C#-Sprachreferenz dokumentiert die zuletzt veröffentlichte Version der C#-Sprache. Außerdem enthält sie eine erste Dokumentation zu Funktionen in der öffentlichen Vorschau für die kommende Sprachversion.
In der Dokumentation werden alle Features identifiziert, die in den letzten drei Versionen der Sprache oder in der aktuellen öffentlichen Vorschau eingeführt wurden.
Tipp
Informationen dazu, wann ein Feature erstmals in C# eingeführt wurde, finden Sie im Artikel zum Versionsverlauf der C#-Sprache.
Memberzugriffsausdruck .
Verwenden Sie das . Token für den Zugriff auf ein Element eines Namespaces oder eines Typs, wie die folgenden Beispiele veranschaulichen:
- Verwenden Sie
.für den Zugriff auf einen geschachtelten Namespace innerhalb eines Namespace, wie im folgenden Beispiel einerusing-Anweisung gezeigt:
using System.Collections.Generic;
- Verwenden Sie
., um einen qualifizierten Namen zu bilden, um auf einen Typ innerhalb eines Namespace zuzugreifen, wie im folgenden Code gezeigt:
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];
Verwenden Sie eine using-Anweisung, um die Verwendung qualifizierter Namen optional zu machen.
- Verwenden Sie
.für den Zugriff auf Typmember, statische und nicht statische, wie im folgenden Code gezeigt:
List<double> constants =
[
Math.PI,
Math.E
];
Console.WriteLine($"{constants.Count} values to show:");
Console.WriteLine(string.Join(", ", constants));
// Output:
// 2 values to show:
// 3.14159265358979, 2.71828182845905
Sie können auch . auf ein Erweiterungsmitglied zugreifen.
Indexeroperator []
Eckige Klammern, in []der Regel greifen Sie auf Array-, Indexer- oder Zeigerelemente zu. Ab C# 12 schließt [] ein Sammlungsausdruck ein.
Arrayzugriff
Im folgenden Beispiel wird der Zugriff auf Elemente des Arrays veranschaulicht:
int[] fib = new int[10];
fib[0] = fib[1] = 1;
for (int i = 2; i < fib.Length; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
Console.WriteLine(fib[fib.Length - 1]); // output: 55
double[,] matrix = new double[2,2];
matrix[0,0] = 1.0;
matrix[0,1] = 2.0;
matrix[1,0] = matrix[1,1] = 3.0;
var determinant = matrix[0,0] * matrix[1,1] - matrix[1,0] * matrix[0,1];
Console.WriteLine(determinant); // output: -3
Wenn sich ein Arrayindex außerhalb der Grenzen der entsprechenden Dimension eines Arrays befindet, löst die Laufzeit ein IndexOutOfRangeException.
Wie im vorherigen Beispiel gezeigt, verwenden Sie eckige Klammern auch zur Deklaration eines Arraytyps oder Instanziierung von Arrayinstanzen.
Weitere Informationen zu Arrays finden Sie unter Arrays.
Indexerzugriff
Im folgenden Beispiel wird der Indexerzugriff anhand des .NET Dictionary<TKey,TValue>-Typs veranschaulicht:
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Mit Indexern können Sie Instanzen eines benutzerdefinierten Typs auf ähnliche Weise indizieren wie die Arrayindizierung. Im Gegensatz zu Arrayindizes, die ganze Zahlen sein müssen, können die Indexerparameter mit einem beliebigen Typ deklariert werden.
Weitere Informationen über Indexer finden Sie unter Indexer.
Andere Verwendungen von „[]“
Weitere Informationen zum Zeigerelementzugriff finden Sie im Abschnitt Zeigerelementzugriff-Operator [] im Artikel Operatoren im Zusammenhang mit Zeigern. Informationen zu Sammlungsausdrücken finden Sie im Artikel zu Sammlungsausdrücken.
Sie verwenden eckige Klammern auch, um Attribute anzugeben:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
Verwenden Sie außerdem eckige Klammern, um Listenmuster für die Verwendung in Musterabgleich oder Tests zu bestimmen.
arr is ([1, 2, ..])
//Specifies that an array starts with (1, 2)
NULL-bedingte Operatoren ?. und ?[]
Ein bedingter Operator mit Null wendet einen Memberzugriffsvorgang (?.) oder einen Elementzugriffsvorgang (?[]) nur dann auf den Operanden an, wenn dieser Operand als nicht null ausgewertet wird. Andernfalls wird nullzurückgegeben. Anders gesagt:
Wenn
aalsnullausgewertet wird, ist das Ergebnis vona?.xodera?[x]null.Wenn
ain einen Wert ungleich NULL ausgewertet wird, ist das Ergebnis vona?.xodera?[x]mit dem Ergebnis vona.xbzw.a[x]identisch.Hinweis
If
a.xora[x]throws an exception,a?.xora?[x]throws the same exception for non-nulla. Wenn es sich z. Ba. um eine Nicht-Null-Arrayinstanz handelt undxsich außerhalb der Grenzen vona,a?[x]löst ein IndexOutOfRangeException.
Die NULL-bedingten Operatoren sind Kurzschlussoperatoren. D.h., wenn ein Vorgang in einer Kette von bedingten Member- oder Elementzugriffsvorgängen null zurückgibt, wird der Rest der Kette nicht ausgeführt. Im folgenden Beispiel wird B nicht ausgewertet, wenn A als null ausgewertet wird, und C wird nicht ausgewertet, wenn A oder B als null ausgewertet wird:
A?.B?.Do(C);
A?.B?[C];
Wenn A NULL sein könnte, aber B und C nicht NULL wären, wenn A nicht NULL ist, müssen Sie nur den NULL-bedingten Operator auf A anwenden:
A?.B.C();
Im vorherigen Beispiel wird B nicht ausgewertet und C() nicht aufgerufen, wenn A NULL ist. Wenn der verkettete Memberzugriff jedoch unterbrochen wird (z. B. durch Klammern wie in (A?.B).C()), erfolgt kein Kurzschluss.
In den folgenden Beispielen wird die Verwendung der ?.- und ?[]-Operatoren veranschaulicht:
double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}
var sum1 = SumNumbers(null, 0);
Console.WriteLine(sum1); // output: NaN
List<double[]?> numberSets =
[
[1.0, 2.0, 3.0],
null
];
var sum2 = SumNumbers(numberSets, 0);
Console.WriteLine(sum2); // output: 6
var sum3 = SumNumbers(numberSets, 1);
Console.WriteLine(sum3); // output: NaN
namespace MemberAccessOperators2;
public static class NullConditionalShortCircuiting
{
public static void Main()
{
Person? person = null;
person?.Name.Write(); // no output: Write() is not called due to short-circuit.
try
{
(person?.Name).Write();
}
catch (NullReferenceException)
{
Console.WriteLine("NullReferenceException");
}; // output: NullReferenceException
}
}
public class Person
{
public required FullName Name { get; set; }
}
public class FullName
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
public void Write() => Console.WriteLine($"{FirstName} {LastName}");
}
Im ersten vorherigen Beispiel wird ebenfalls der null-coalescing-Operator ?? verwendet, um einen alternativen Ausdruck zu definieren, der ausgewertet wird, falls das Ergebnis einer null-conditional-Operation null ist.
Wenn a.x oder a[x] vom Werttyp T ist, der keine NULL-Werte zulässt, ist a?.x oder a?[x] vom entsprechenden Werttyp T?, der keine NULL-Werte zulässt. Wenn Sie einen Ausdruck vom Typ T benötigen, wenden Sie den NULL-Sammeloperator ?? auf einen NULL-bedingten Ausdruck an, wie im folgenden Beispiel gezeigt:
int GetSumOfFirstTwoOrDefault(int[]? numbers)
{
if ((numbers?.Length ?? 0) < 2)
{
return 0;
}
return numbers[0] + numbers[1];
}
Console.WriteLine(GetSumOfFirstTwoOrDefault(null)); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([])); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([3, 4, 5])); // output: 7
Wenn Sie im vorherigen Beispiel nicht den ??-Operator verwenden und numbers den Wert null hat, wird numbers?.Length < 2 als false ausgewertet.
Hinweis
Der ?.-Operator wertet seinen linken Operanden höchstens einmal aus und stellt sicher, dass er nicht mehr zu null geändert werden kann, nachdem er als nicht-null überprüft wurde.
Ab C# 14 ist die Zuweisung mit einem Null-Ausdruck für bedingten Zugriff (?. und ?[]) für Verweistypen zulässig. Sehen Sie sich zum Beispiel die folgende Methode an:
person?.FirstName = "Scott";
messages?[5] = "five";
Im vorherigen Beispiel wird die Zuweisung zu einer Eigenschaft und ein indiziertes Element für einen Verweistyp gezeigt, der null sein kann. Ein wichtiges Verhalten für diese Zuordnung ist, dass der Ausdruck auf der rechten Seite von = nur ausgewertet wird, wenn bekannt ist, dass die linke Seite nicht null ist. Im folgenden Code wird die Funktion GenerateNextIndex beispielsweise nur aufgerufen, wenn das values Array nicht null ist. Wenn das values Array null ist, GenerateNextIndex wird er nicht aufgerufen:
values?[2] = GenerateNextIndex();
int GenerateNextIndex() => index++;
Mit anderen Worten, der vorangehende Code entspricht dem folgenden Code, der eine if Anweisung für die NULL-Überprüfung verwendet:
if (values is not null)
{
values[2] = GenerateNextIndex();
}
Neben der Zuordnung ist jede Form der zusammengesetzten Zuordnung, z += . B. oder -=, zulässig. Inkrementierung (++) und Dekrement (--) sind jedoch nicht zulässig.
Diese Erweiterung klassifiziert einen Null-bedingten Ausdruck nicht als eine Variable. Es kann weder ref zugewiesen noch einer ref Variablen zugewiesen oder als refout Argument an eine Methode übergeben werden.
Threadsicherer Delegataufruf
Verwenden Sie den ?. Operator, um zu überprüfen, ob eine Stellvertretung nicht null ist und sie auf threadsichere Weise aufrufen (z. B. wenn Sie ein Ereignis auslösen), wie der folgende Code zeigt:
PropertyChanged?.Invoke(…)
Dieser Code entspricht dem folgenden Code:
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
Das vorangehende Beispiel ist eine threadsichere Möglichkeit, um sicherzustellen, dass nur ein handler ungleich NULL aufgerufen wird. Da Delegatinstanzen unveränderlich sind, kann kein Thread das Objekt ändern, auf das von der lokalen handler-Variable verwiesen wird. Insbesondere wenn der von einem anderen Thread ausgeführte Code das Abonnement des PropertyChanged-Ereignisses aufhebt und PropertyChanged zu null wird, bevor handler aufgerufen wird, bleibt das Objekt unverändert, auf das von handler verwiesen wird.
Aufrufausdruck „()“
Verwenden Sie Klammern () zum Aufrufen einer Methode, oder rufen Sie einen Delegaten auf.
Der folgende Code veranschaulicht, wie eine Methode mit oder ohne Argumente aufgerufen und ein Delegat aufgerufen wird:
Action<int> display = s => Console.WriteLine(s);
List<int> numbers =
[
10,
17
];
display(numbers.Count); // output: 2
numbers.Clear();
display(numbers.Count); // output: 0
Sie verwenden auch Klammern, wenn Sie einen Konstruktor mithilfe des new Operators aufrufen.
Andere Verwendungen von „()“
Mit Klammern passen Sie auch die Reihenfolge an, in der Vorgänge in einem Ausdruck ausgewertet werden sollen. Weitere Informationen finden Sie unter C#-Operatoren.
Cast-Ausdrücke, die explizite Typkonvertierungen ausführen, verwenden ebenfalls Klammern.
Index vom Endeoperator ^
Sie können Index- und Bereichsoperatoren mit einem Typ verwenden, der gezählt werden kann. Ein zählungsfähiger Typ verfügt über eine int Eigenschaft mit dem Namen Count oder Length mit einem Barrierefreien get Accessor. Auch Sammlungsausdrücke basieren auf zählbaren Typen.
Hinweis
Eindimensionale Arrays können gezählt werden. Mehrdimensionale Arrays sind nicht vorhanden. Sie können die ^ Operatoren und .. (Bereich) nicht in mehrdimensionalen Arrays verwenden.
Der ^-Operator gibt die Elementposition vom Ende einer Sequenz ausgehend an. Für eine Sequenz der Länge length verweist ^n auf das Element mit dem Offset length - n vom Beginn einer Sequenz. ^1 zeigt beispielsweise auf das letzte Element einer Sequenz, und ^length zeigt auf das erste Element einer Sequenz.
int[] xs = [0, 10, 20, 30, 40];
int last = xs[^1];
Console.WriteLine(last); // output: 40
List<string> lines = ["one", "two", "three", "four"];
string prelast = lines[^2];
Console.WriteLine(prelast); // output: three
string word = "Twenty";
Index toFirst = ^word.Length;
char first = word[toFirst];
Console.WriteLine(first); // output: T
Wie das vorherige Beispiel zeigt, weist Ausdruck ^e den Typ System.Index auf. In Ausdruck ^e muss das Ergebnis von e implizit in int konvertierbar sein.
Sie können auch den ^-Operator mit dem Bereichsoperator verwenden, um einen Bereich von Indizes zu erstellen. Weitere Informationen finden Sie unter Indizes und Bereiche.
Ab C# 13 können Sie den Index vom Endoperator in ^einem Objektinitialisierer verwenden.
Bereichsoperator ..
Der Operator .. gibt den Anfang und das Ende eines Bereichs von Indizes als seine Operanden an. Der linke Operand ist der inklusive Anfang eines Bereichs. Der rechte Operand ist das exklusive Ende eines Bereichs. Jeder Operand kann ein Index vom Anfang oder vom Ende einer Sequenz sein, wie das folgende Beispiel zeigt:
int[] numbers = [0, 10, 20, 30, 40, 50];
int start = 1;
int amountToTake = 3;
int[] subset = numbers[start..(start + amountToTake)];
Display(subset); // output: 10 20 30
int margin = 1;
int[] inner = numbers[margin..^margin];
Display(inner); // output: 10 20 30 40
string line = "one two three";
int amountToTakeFromEnd = 5;
Range endIndices = ^amountToTakeFromEnd..^0;
string end = line[endIndices];
Console.WriteLine(end); // output: three
void Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
Wie das vorherige Beispiel zeigt, weist Ausdruck ^e den Typ System.Index auf. In Ausdruck a..b muss das Ergebnis von a und b implizit in Int32 oder Index konvertierbar sein.
Wichtig
Implizite Konvertierungen von int in Index lösen eine ArgumentOutOfRangeException aus, wenn der Wert negativ ist.
Sie können Operanden des Operators .. auslassen, um einen Bereich ohne Ende abzurufen:
a..entsprichta..^0a..entsprichta..^0a..entsprichta..^0
int[] numbers = [0, 10, 20, 30, 40, 50];
int amountToDrop = numbers.Length / 2;
int[] rightHalf = numbers[amountToDrop..];
Display(rightHalf); // output: 30 40 50
int[] leftHalf = numbers[..^amountToDrop];
Display(leftHalf); // output: 0 10 20
int[] all = numbers[..];
Display(all); // output: 0 10 20 30 40 50
void Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
In der folgende Tabelle werden verschiedene Möglichkeiten aufgeführt, um Sammlungsbereiche auszudrücken:
| Bereichsoperatorausdruck | BESCHREIBUNG |
|---|---|
.. |
Alle Werte in der Sammlung |
..end |
Werte von Anfang bis exklusive end |
start.. |
Werte von inklusive start bis zum Ende |
start..end |
Werte von inklusive start bis exklusive end |
^start.. |
Werte von inklusive start bis zum Ende, vom Ende aus gezählt |
..^end |
Werte vom Anfang bis exklusive end, vom Ende aus gezählt |
start..^end |
Werte von inklusive start bis exklusive end, vom Ende aus gezählt |
^start..^end |
Werte von inklusive start bis exklusive end, beide vom Ende aus gezählt |
Im folgenden Beispiel wird die Auswirkung aller in der vorherigen Tabelle aufgeführten Bereiche veranschaulicht:
int[] oneThroughTen =
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
];
Write(oneThroughTen, ..);
Write(oneThroughTen, ..3);
Write(oneThroughTen, 2..);
Write(oneThroughTen, 3..5);
Write(oneThroughTen, ^2..);
Write(oneThroughTen, ..^3);
Write(oneThroughTen, 3..^4);
Write(oneThroughTen, ^4..^2);
static void Write(int[] values, Range range) =>
Console.WriteLine($"{range}:\t{string.Join(", ", values[range])}");
// Sample output:
// 0..^0: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
// 0..3: 1, 2, 3
// 2..^0: 3, 4, 5, 6, 7, 8, 9, 10
// 3..5: 4, 5
// ^2..^0: 9, 10
// 0..^3: 1, 2, 3, 4, 5, 6, 7
// 3..^4: 4, 5, 6
// ^4..^2: 7, 8
Weitere Informationen finden Sie unter Indizes und Bereiche.
Das ..-Token wird auch für das Spread-Element in einem Sammlungsausdruck verwendet.
Operatorüberladbarkeit
Sie können die .Operatoren , (), und ^.. die Operatoren nicht überladen. Der [] Operator ist auch ein nicht überladener Operator. Verwenden Sie Indexer zur Unterstützung der Indizierung mit benutzerdefinierten Typen.
C#-Sprachspezifikation
Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation:
Weitere Informationen zu Indizes und Bereichen finden Sie unter Hinweis zum Featurevorschlag.