Operátory a výrazy přístupu členů – tečky, indexer a operátory volání.
Pro přístup k členu typu použijete několik operátorů a výrazů. Mezi tyto operátory patří přístup člena (.
), prvek pole nebo přístup indexeru ([]
), index-from-end (^
), range (..
), operátory s podmíněnou hodnotou null (?.
a ?[]
) a vyvolání metody (()
). Patří mezi ně operátory přístupu s podmíněným přístupem s hodnotou null (?.
) a indexerem (?[]
).
.
(přístup člena): přístup k členu oboru názvů nebo typu[]
(přístup k elementu pole nebo indexeru):: přístup k prvku pole nebo indexeru typu?.
a?[]
(podmíněné operátory s hodnotou null):: Provedení operace přístupu člena nebo elementu pouze v případě, že operand nemá hodnotu null.()
(vyvolání): volání přístupové metody nebo vyvolání delegáta^
(index od konce): označuje, že pozice prvku je od konce sekvence...
(rozsah): určení rozsahu indexů, které můžete použít k získání rozsahu sekvenčních prvků
Výraz přístupu člena .
Token použijete .
pro přístup k členu oboru názvů nebo typu, jak ukazují následující příklady:
- Slouží
.
k přístupu k vnořenému oboru názvů v rámci oboru názvů, jak ukazuje následující příklad direktivyusing
:
using System.Collections.Generic;
- Slouží
.
k vytvoření kvalifikovaného názvu pro přístup k typu v rámci oboru názvů, jak ukazuje následující kód:
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];
Použití direktivy using
k použití kvalifikovaných názvů volitelné.
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
Můžete také použít .
přístup k metodě rozšíření.
Operátor indexeru []
Hranaté závorky , []
se obvykle používají pro přístup k prvkům pole, indexeru nebo ukazatele. Počínaje jazykem C# 12 []
uzavře výraz kolekce.
Přístup k poli
Následující příklad ukazuje přístup k prvkům pole:
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
Pokud je index pole mimo hranice odpovídající dimenze pole, IndexOutOfRangeException vyvolá se.
Jak ukazuje předchozí příklad, použijete také hranaté závorky, když deklarujete typ pole nebo vytvoříte instanci pole.
Další informace o polích naleznete v tématu Pole.
Přístup k indexeru
Následující příklad používá typ .NET Dictionary<TKey,TValue> k předvedení přístupu indexeru:
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Indexery umožňují indexovat instance uživatelem definovaného typu podobným způsobem jako indexování pole. Na rozdíl od indexů pole, které musí být celé číslo, lze parametry indexeru deklarovat jako jakýkoli typ.
Další informace o indexerech naleznete v tématu Indexery.
Další využití []
Informace o přístupu k prvkům ukazatele naleznete v části Přístup k prvku ukazatele [] oddílu Ukazatele související operátory článku. Informace o výrazech kolekce naleznete v článku výrazy kolekce.
K určení atributů také použijete hranaté závorky:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
Podmíněné operátory ?.
s hodnotou Null a ?[]
Podmíněný operátor s hodnotou null použije operaci přístupu člena (?.
) nebo elementu (?[]
) na svůj operand pouze v případě, že se tento operand vyhodnotí jako nenulový; v opačném případě vrátí null
. Jinými slovy:
Pokud
a
se vyhodnotí jakonull
, výsledeka?.x
neboa?[x]
jenull
.Pokud
a
se vyhodnotí na hodnotu non-null, výsledeka?.x
neboa?[x]
je stejný jako výsledeka.x
neboa[x]
, v uvedeném pořadí.Poznámka:
Pokud
a.x
neboa[x]
vyvolá výjimku,a?.x
neboa?[x]
by vyvolá stejnou výjimku pro non-nulla
. Pokuda
je například instance pole, která není null ax
je mimo hranicea
,a?[x]
vyvolá výjimku IndexOutOfRangeException.
Podmíněné operátory s hodnotou null jsou zkratové. To znamená, že pokud jedna operace v řetězci operací přístupu podmíněného člena nebo elementu vrátí null
, zbytek řetězce se nespustí. V následujícím příkladu se nevyhodnocuje, B
pokud A
se vyhodnotí null
jako a C
nevyhodnocuje, jestli A
nebo B
se vyhodnotí jako null
:
A?.B?.Do(C);
A?.B?[C];
Pokud A
může mít hodnotu null, ale B
pokud C
hodnota A není null, musíte použít pouze podmíněný operátor null na A
:
A?.B.C();
V předchozím příkladu se nevyhodnocuje a C()
není volána, B
pokud A
má hodnotu null. Pokud je však přístup zřetězeného člena přerušen, například závorky jako v (A?.B).C()
případě , zkratování se nestane.
Následující příklady ukazují použití ?.
operátorů a ?[]
operátorů:
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}");
}
První z předchozích dvou příkladů také používá operátor ??
null-coalescing k určení alternativního výrazu, který se má vyhodnotit v případě, že je null
výsledkem operace s podmínkou null .
Je-li a.x
nebo a[x]
je typu hodnoty, která není nullable T
, a?.x
nebo a?[x]
je odpovídající typ T?
hodnoty nullable . Pokud potřebujete výraz typu T
, použijte operátor ??
null-coalescing na podmíněný výraz null, jak ukazuje následující příklad:
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
Pokud v předchozím příkladu operátor nepoužíváte ??
, numbers?.Length < 2
vyhodnotí se, false
kdy numbers
je null
.
Poznámka:
Operátor ?.
vyhodnotí levý operand ne více než jednou a zaručuje, že ho nelze změnit na null
po ověření jako nenulové.
Operátor přístupu ?.
k podmíněnému členu s hodnotou null se také označuje jako operátor Elvis.
Vyvolání delegáta bezpečného pro přístup z více vláken
Pomocí operátoru ?.
zkontrolujte, jestli delegát nemá hodnotu null a vyvolá ho bezpečným způsobem vlákna (například při vyvolání události), jak ukazuje následující kód:
PropertyChanged?.Invoke(…)
Tento kód je ekvivalentní následujícímu kódu:
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
Předchozí příklad představuje bezpečný způsob, jak zajistit, že se vyvolá pouze nenulová handler
hodnota. Vzhledem k tomu, že instance delegátů jsou neměnné, nemůže vlákno změnit objekt odkazovaný místní proměnnou handler
. Zejména pokud kód spuštěný jiným vláknem odhlásí událost PropertyChanged
a PropertyChanged
stane se null
před handler
vyvoláním, objekt odkazovaný handler
na něj zůstane nedotčen.
Výraz vyvolání ()
K volání metody nebo vyvolání delegáta použijte závorky()
.
Následující příklad ukazuje, jak volat metodu s argumenty nebo bez argumentů a vyvolat delegáta:
Action<int> display = s => Console.WriteLine(s);
List<int> numbers =
[
10,
17
];
display(numbers.Count); // output: 2
numbers.Clear();
display(numbers.Count); // output: 0
Při vyvolání konstruktoru s operátorem new
také použijete závorky.
Další využití ()
Pomocí závorek také upravíte pořadí, ve kterém se mají vyhodnocovat operace ve výrazu. Další informace najdete v tématu Operátory jazyka C#.
Přetypování výrazů, které provádějí explicitní převody typů, také používají závorky.
Index od koncového operátoru ^
Operátory indexu a rozsahu lze použít s typem, který lze spočítat. Počítaný typ je typ, který má int
vlastnost s názvem buď Count
nebo Length
s přístupným get
příslušenstvím. Výrazy kolekce také spoléhají na počítané typy.
Operátor ^
označuje pozici prvku od konce sekvence. Pro sekvenci délky length
^n
odkazuje na prvek s posunem length - n
od začátku sekvence. Například ^1
odkazuje na poslední prvek sekvence a ^length
odkazuje na první prvek sekvence.
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
Jak ukazuje předchozí příklad, výraz ^e
je typu System.Index . Ve výrazu ^e
musí být výsledek e
implicitně konvertibilní na int
.
Pomocí operátoru rozsahu ^
můžete také vytvořit rozsah indexů. Další informace naleznete v tématu Indexy a rozsahy.
Počínaje jazykem C# 13 lze index z koncového operátoru použít v inicializátoru objektů.
Operátor rozsahu ..
Operátor ..
určuje začátek a konec rozsahu indexů jako jeho operandy. Levý operand je inkluzivním začátkem rozsahu. Pravý operand je výhradním koncem rozsahu. Jeden z operandů může být indexem od začátku nebo od konce sekvence, jak ukazuje následující příklad:
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));
Jak ukazuje předchozí příklad, výraz a..b
je typu System.Range . Ve výrazu a..b
musí být výsledky a
a b
musí být implicitně konvertibilní na Int32 nebo Index.
Důležité
Implicitní převody z int
hodnoty na Index
vyvolání, když je hodnota záporná ArgumentOutOfRangeException .
Pokud chcete získat otevřený rozsah, můžete vynechat některý z operandů ..
operátoru:
a..
je ekvivalentnía..^0
..b
je ekvivalentní0..b
..
je ekvivalentní0..^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));
Následující tabulka ukazuje různé způsoby vyjádření rozsahů kolekcí:
Výraz operátoru rozsahu | Popis |
---|---|
.. |
Všechny hodnoty v kolekci. |
..end |
Hodnoty od začátku až po end výhradně. |
start.. |
Hodnoty od start inkluzí do konce. |
start..end |
Hodnoty od inkluzivního start end po výhradně. |
^start.. |
Hodnoty od inkluzivního start po koncové počítání od konce. |
..^end |
Hodnoty od začátku po end výhradní počítání od konce. |
start..^end |
Hodnoty od start inkluzivního po end výhradní počítání od konce. |
^start..^end |
Hodnoty od start inkluzivního po end výhradně oba počítání od konce. |
Následující příklad ukazuje účinek použití všech oblastí uvedených v předchozí tabulce:
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
Další informace naleznete v tématu Indexy a rozsahy.
Token ..
se také používá pro prvek šíření ve výrazu kolekce.
Přetížení operátoru
Operátory .
, ()
, ^
a ..
nelze přetížit. Operátor []
je také považován za nepřetížitelný operátor. Pomocí indexerů můžete podporovat indexování s uživatelsky definovanými typy.
specifikace jazyka C#
Další informace najdete v následujících částech specifikace jazyka C#:
Další informace o indexech a rozsazích najdete v poznámce k návrhu funkce.