Operatoren und Ausdrücke für den Memberzugriff (C#-Referenz)Member access operators and expressions (C# reference)

Sie können die folgenden Operatoren und Ausdrücke zum Zugriff auf einen Typmember verwenden:You can use the following operators and expressions when you access a type member:

Memberzugriffsausdruck „.“Member access expression .

Sie verwenden das .-Token für den Zugriff auf einen Member eines Namespace oder eines Typs, wie die folgenden Beispiele veranschaulichen:You use the . token to access a member of a namespace or a type, as the following examples demonstrate:

  • Verwenden Sie . für den Zugriff auf einen geschachtelten Namespace innerhalb eines Namespace, wie im folgenden Beispiel einer using-Anweisung gezeigt:Use . to access a nested namespace within a namespace, as the following example of a using directive shows:

    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:Use . to form a qualified name to access a type within a namespace, as the following code shows:

    System.Collections.Generic.IEnumerable<int> numbers = new int[] { 1, 2, 3 };
    

    Verwenden Sie eine using-Anweisung, um die Verwendung qualifizierter Namen optional zu machen.Use a using directive to make the use of qualified names optional.

  • Verwenden Sie . für den Zugriff auf Typmember, statische und nicht statische, wie im folgenden Code gezeigt:Use . to access type members, static and non-static, as the following code shows:

    var constants = new List<double>();
    constants.Add(Math.PI);
    constants.Add(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 . verwenden, um auf eine Erweiterungsmethode zuzugreifen.You can also use . to access an extension method.

Indexeroperator []Indexer operator []

Eckige Klammern ([]) werden in der Regel für den Zugriff auf Arrays, Indexer oder Zeigerelemente verwendet.Square brackets, [], are typically used for array, indexer, or pointer element access.

ArrayzugriffArray access

Im folgenden Beispiel wird der Zugriff auf Elemente des Arrays veranschaulicht:The following example demonstrates how to access array elements:

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 ein Arrayindex sich außerhalb der Grenzen der entsprechenden Dimension eines Arrays befindet, wird eine IndexOutOfRangeException ausgelöst.If an array index is outside the bounds of the corresponding dimension of an array, an IndexOutOfRangeException is thrown.

Wie im vorherigen Beispiel gezeigt, verwenden Sie eckige Klammern auch zur Deklaration eines Arraytyps oder Instanziierung von Arrayinstanzen.As the preceding example shows, you also use square brackets when you declare an array type or instantiate an array instance.

Weitere Informationen zu Arrays finden Sie unter Arrays.For more information about arrays, see Arrays.

IndexerzugriffIndexer access

Im folgenden Beispiel wird der Indexerzugriff anhand des .NET Dictionary<TKey,TValue>-Typs veranschaulicht:The following example uses the .NET Dictionary<TKey,TValue> type to demonstrate indexer access:

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 wie ein Array indizieren.Indexers allow you to index instances of a user-defined type in the similar way as array indexing. Im Gegensatz zu Arrayindizes, die ganze Zahlen sein müssen, können die Indexerparameter mit einem beliebigen Typ deklariert werden.Unlike array indices, which must be integer, the indexer parameters can be declared to be of any type.

Weitere Informationen über Indexer finden Sie unter Indexer.For more information about indexers, see Indexers.

Andere Verwendungen von „[]“Other usages of []

Weitere Informationen zum Zeigerelementzugriff finden Sie im Abschnitt Zeigerelementzugriff-Operator [] im Artikel Operatoren im Zusammenhang mit Zeigern.For information about pointer element access, see the Pointer element access operator [] section of the Pointer related operators article.

Sie verwenden eckige Klammern auch, um Attribute anzugeben:You also use square brackets to specify attributes:

[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}

NULL-bedingte Operatoren „?.“Null-conditional operators ?. und „?[]“and ?[]

Ein in C# 6 und höher verfügbarer NULL-bedingter Operator wendet nur dann einen Memberzugriffsvorgang (?.) oder Elementzugriffsvorgang (?[]) auf seinen Operanden an, wenn dieser Operand als ungleich NULL ausgewertet wird. Andernfalls gibt er null zurück.Available in C# 6 and later, a null-conditional operator applies a member access, ?., or element access, ?[], operation to its operand only if that operand evaluates to non-null; otherwise, it returns null. Dies bedeutet:That is,

  • Wenn a als null ausgewertet wird, ist das Ergebnis von a?.x oder a?[x] null.If a evaluates to null, the result of a?.x or a?[x] is null.

  • Wenn a in einen Wert ungleich NULL ausgewertet wird, ist das Ergebnis von a?.x oder a?[x] mit dem Ergebnis von a.x bzw. a[x] identisch.If a evaluates to non-null, the result of a?.x or a?[x] is the same as the result of a.x or a[x], respectively.

    Hinweis

    Wenn a.x oder a[x] eine Ausnahme auslöst, würden a?.x oder a?[x] für a ungleich NULL dieselbe Ausnahme auslösen.If a.x or a[x] throws an exception, a?.x or a?[x] would throw the same exception for non-null a. Wenn a z. B. eine Arrayinstanz ungleich NULL ist und x außerhalb der Grenzen von a liegt, löst a?[x] eine IndexOutOfRangeException aus.For example, if a is a non-null array instance and x is outside the bounds of a, a?[x] would throw an IndexOutOfRangeException.

Die NULL-bedingten Operatoren sind Kurzschlussoperatoren.The null-conditional operators are short-circuiting. 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.That is, if one operation in a chain of conditional member or element access operations returns null, the rest of the chain doesn't execute. 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:In the following example, B is not evaluated if A evaluates to null and C is not evaluated if A or B evaluates to null:

A?.B?.Do(C);
A?.B?[C];

Im folgenden Beispiel wird die Verwendung des ?.- und ?[]-Operators veranschaulicht:The following example demonstrates the usage of the ?. and ?[] operators:

double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
    return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}

var sum1 = SumNumbers(null, 0);
Console.WriteLine(sum1);  // output: NaN

var numberSets = new List<double[]>
{
    new[] { 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

Im vorangehenden Beispiel wird auch der NULL-Sammeloperator?? zum Angeben eines alternativen Ausdrucks zum Auswerten verwendet, falls das Ergebnis eines NULL-bedingten Vorgangs null ist.The preceding example also uses the null-coalescing operator ?? to specify an alternative expression to evaluate in case the result of a null-conditional operation is null.

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.If a.x or a[x] is of a non-nullable value type T, a?.x or a?[x] is of the corresponding nullable value type T?. 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:If you need an expression of type T, apply the null-coalescing operator ?? to a null-conditional expression, as the following example shows:

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(new int[0]));  // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault(new[] { 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.In the preceding example, if you don't use the ?? operator, numbers?.Length < 2 evaluates to false when numbers is null.

Der NULL-bedingte Memberzugriffsoperator ?. wird auch als Elvis-Operator bezeichnet.The null-conditional member access operator ?. is also known as the Elvis operator.

Hinweis

In C# 8 beendet der NULL-tolerante Operator die Liste mit den vorangehenden NULL-bedingten Vorgängen.In C# 8, the null-forgiving operator terminates the list of preceding null-conditional operations. Der Ausdruck x?.y!.z wird beispielsweise als (x?.y)!.z analysiert.For example, the expression x?.y!.z is parsed as (x?.y)!.z. Aufgrund dieser Interpretation wird z ausgewertet, auch wenn x null ist, was zu NullReferenceException führen kann.Due to this interpretation, z is evaluated even if x is null, which may result in a NullReferenceException.

Threadsicherer DelegataufrufThread-safe delegate invocation

Verwenden Sie den ?.-Operator, um zu überprüfen, ob ein Delegat ungleich NULL ist, und ihn auf threadsichere Weise aufzurufen (z.B. wenn Sie ein Ereignis auslösen), wie der folgende Code zeigt:Use the ?. operator to check if a delegate is non-null and invoke it in a thread-safe way (for example, when you raise an event), as the following code shows:

PropertyChanged?.Invoke(…)

Dass Code dem folgenden Code entspricht, den Sie in C# 5 oder früher verwenden würden:That code is equivalent to the following code that you would use in C# 5 or earlier:

var handler = this.PropertyChanged;
if (handler != null)
{
    handler(…);
}

Dies ist eine threadsichere Möglichkeit, um sicherzustellen, dass nur ein handler ungleich NULL aufgerufen wird.That is a thread-safe way to ensure that only a non-null handler is invoked. Da Delegatinstanzen unveränderlich sind, kann kein Thread das Objekt ändern, auf das von der lokalen handler-Variable verwiesen wird.Because delegate instances are immutable, no thread can change the object referenced by the handler local variable. 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.In particular, if the code executed by another thread unsubscribes from the PropertyChanged event and PropertyChanged becomes null before handler is invoked, the object referenced by handler remains unaffected. Der ?.-Operator wertet seinen linken Operanden nicht mehr als einmal aus, um sicherzustellen, dass er nicht in null geändert werden kann, nachdem bestätigt wurde, dass er ungleich NULL ist.The ?. operator evaluates its left-hand operand no more than once, guaranteeing that it cannot be changed to null after being verified as non-null.

Aufrufausdruck „()“Invocation expression ()

Verwenden Sie Klammern () zum Aufrufen einer Methode, oder rufen Sie einen Delegaten auf.Use parentheses, (), to call a method or invoke a delegate.

Im folgenden Beispiel wird der Aufruf einer Methode mit oder ohne Argumente sowie eines Delegaten veranschaulicht:The following example demonstrates how to call a method, with or without arguments, and invoke a delegate:

Action<int> display = s => Console.WriteLine(s);

var numbers = new List<int>();
numbers.Add(10);
numbers.Add(17);
display(numbers.Count);   // output: 2

numbers.Clear();
display(numbers.Count);   // output: 0

Klammern verwenden Sie auch beim Aufrufen eines Konstruktors mit dem new-Operator.You also use parentheses when you invoke a constructor with the new operator.

Andere Verwendungen von „()“Other usages of ()

Mit Klammern passen Sie auch die Reihenfolge an, in der Vorgänge in einem Ausdruck ausgewertet werden sollen.You also use parentheses to adjust the order in which to evaluate operations in an expression. Weitere Informationen finden Sie unter C#-Operatoren.For more information, see C# operators.

Cast-Ausdrücke, die explizite Typkonvertierungen ausführen, verwenden ebenfalls Klammern.Cast expressions, which perform explicit type conversions, also use parentheses.

Index vom Endeoperator ^Index from end operator ^

Der ^-Operator ist in C# 8.0 und höher verfügbar und gibt die Elementposition vom Ende einer Sequenz an.Available in C# 8.0 and later, the ^ operator indicates the element position from the end of a sequence. Für eine Sequenz der Länge length verweist ^n auf das Element mit dem Offset length - n vom Beginn einer Sequenz.For a sequence of length length, ^n points to the element with offset length - n from the start of a sequence. ^1 zeigt beispielsweise auf das letzte Element einer Sequenz, und ^length zeigt auf das erste Element einer Sequenz.For example, ^1 points to the last element of a sequence and ^length points to the first element of a sequence.

int[] xs = new[] { 0, 10, 20, 30, 40 };
int last = xs[^1];
Console.WriteLine(last);  // output: 40

var lines = new List<string> { "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.As the preceding example shows, expression ^e is of the System.Index type. In Ausdruck ^e muss das Ergebnis von e implizit in int konvertierbar sein.In expression ^e, the result of e must be implicitly convertible to int.

Sie können auch den ^-Operator mit dem Bereichsoperator verwenden, um einen Bereich von Indizes zu erstellen.You can also use the ^ operator with the range operator to create a range of indices. Weitere Informationen finden Sie unter Indizes und Bereiche.For more information, see Indices and ranges.

Bereichsoperator .Range operator ..

Der Operator .., der in C# 8.0 und höher verfügbar ist, gibt den Anfang und das Ende eines Bereichs von Indizes als seine Operanden an.Available in C# 8.0 and later, the .. operator specifies the start and end of a range of indices as its operands. Der linke Operand ist der inklusive Anfang eines Bereichs.The left-hand operand is an inclusive start of a range. Der rechte Operand ist das exklusive Ende eines Bereichs.The right-hand operand is an exclusive end of a range. Beide Operanden können ein Index vom Anfang oder vom Ende einer Sequenz sein, wie das folgende Beispiel zeigt:Either of operands can be an index from the start or from the end of a sequence, as the following example shows:

int[] numbers = new[] { 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 der Ausdruck a..b den Typ System.Range auf.As the preceding example shows, expression a..b is of the System.Range type. In Ausdruck a..b muss das Ergebnis von a und b implizit in int oder Index konvertierbar sein.In expression a..b, the results of a and b must be implicitly convertible to int or Index.

Sie können Operanden des Operators .. auslassen, um einen Bereich ohne Ende abzurufen:You can omit any of the operands of the .. operator to obtain an open-ended range:

  • a.. entspricht a..^0a.. is equivalent to a..^0
  • ..b entspricht 0..b..b is equivalent to 0..b
  • .. entspricht 0..^0.. is equivalent to 0..^0
int[] numbers = new[] { 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));

Weitere Informationen finden Sie unter Indizes und Bereiche.For more information, see Indices and ranges.

OperatorüberladbarkeitOperator overloadability

Die Operatoren ., (), ^ und .. können nicht überladen werden.The ., (), ^, and .. operators cannot be overloaded. Der []-Operator wird auch als nicht überladbarer Operator betrachtet.The [] operator is also considered a non-overloadable operator. Verwenden Sie Indexer zur Unterstützung der Indizierung mit benutzerdefinierten Typen.Use indexers to support indexing with user-defined types.

C#-SprachspezifikationC# language specification

Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation:For more information, see the following sections of the C# language specification:

Weitere Informationen zu Indizes und Bereichen finden Sie unter Hinweis zum Featurevorschlag.For more information about indices and ranges, see the feature proposal note.

Siehe auchSee also