Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Aby uzyskać dostęp do elementu członkowskiego typu, należy użyć kilku operatorów i wyrażeń. Operatory dostępu do składowych obejmują dostęp do składowych (.
), element tablicy lub dostęp indeksatora ([]
), indeks od końca (^
), zakres (..
), operatory warunkowe wartości null (?.
i ?[]
) oraz wywołanie metody (()
). Te operatory obejmują operatory dostępu warunkowego o wartości null (?.
) oraz operatory dostępu indeksatora (?[]
).
.
(dostęp do członka): aby uzyskać dostęp do członka przestrzeni nazw lub typu[]
(dostęp do elementu tablicy lub indeksatora): aby uzyskać dostęp do elementu tablicy lub indeksatora typu?.
i?[]
(operatory warunkowe o wartości null): aby wykonać operację dostępu do elementu członkowskiego lub elementu tylko wtedy, gdy operand ma wartość inną niż null()
(wywołanie): wywołanie metody dostępu lub wywołanie delegata^
(indeks od końca): aby wskazać, że pozycja elementu pochodzi od końca sekwencji..
(zakres): aby określić zakres indeksów, których można użyć do uzyskania zakresu elementów sekwencji
Wyrażenie dostępu do składowych .
Używasz tokenu .
do uzyskiwania dostępu do członka przestrzeni nazw lub typu, co pokazują poniższe przykłady:
- Użyj polecenia
.
do uzyskania dostępu do zagnieżdżonej przestrzeni nazw w ramach przestrzeni nazw, jak pokazano na poniższym przykładzie dyrektywyusing
:
using System.Collections.Generic;
- Użyj
.
do utworzenia kwalifikowanej nazwy, aby uzyskać dostęp do typu w przestrzeni nazw, jak pokazuje poniższy kod:
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];
Użyj dyrektywy using
, aby opcjonalnie używać nazw kwalifikowanych.
- Użyj
.
do uzyskania dostępu do składowych typu: statycznych i niestatycznych, jak pokazuje poniższy kod:
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
Możesz również użyć .
do uzyskania dostępu do metody rozszerzenia .
Operator indeksatora []
Nawiasy kwadratowe, []
, są zwykle używane do uzyskiwania dostępu do tablicy, indeksatora lub elementu wskazywanego wskaźnikiem. Począwszy od języka C# 12, []
otacza wyrażenie kolekcji.
Dostęp do tablicy
W poniższym przykładzie pokazano, jak uzyskać dostęp do elementów tablicy:
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
Jeśli indeks tablicy znajduje się poza granicami odpowiadającego wymiaru tablicy, rzucany jest IndexOutOfRangeException.
Jak pokazano w poprzednim przykładzie, nawiasy kwadratowe są używane podczas deklarowania typu tablicy lub tworzenia jej wystąpienia.
Aby uzyskać więcej informacji na temat tablic, zobacz Tablice.
Dostęp indeksatora
W poniższym przykładzie użyto typu .NET Dictionary<TKey,TValue>, aby zademonstrować dostęp indeksatora.
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Indeksatory umożliwiają indeksowanie wystąpień typu zdefiniowanego przez użytkownika w podobny sposób jak indeksowanie tablicy. W przeciwieństwie do indeksów tablicowych, które muszą być liczbą całkowitą, parametry indeksatora można zadeklarować jako dowolny typ.
Aby uzyskać więcej informacji na temat indeksatorów, zobacz Indeksatory.
Inne użycia []
Aby uzyskać informacje o dostępie do elementu wskaźnika, zobacz sekcję Operator dostępu do elementu wskaźnika [] w artykule Operatory związane ze wskaźnikami. Aby uzyskać informacje na temat wyrażeń kolekcji, zapoznaj się z artykułem o wyrażeniach kolekcji.
Można również użyć nawiasów kwadratowych, aby określić atrybuty:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
Ponadto nawiasy kwadratowe mogą służyć do wyznaczania wzorców listy do użycia w dopasowywaniu lub testowaniu wzorców.
arr is ([1, 2, ..])
//Specifies that an array starts with (1, 2)
Operatory warunkowe dla wartości null ?.
i ?[]
Operator warunkowo-nullowy stosuje operację dostępu do składowej () lub dostępu do elementu (?.
) do operandu tylko wtedy, gdy operand jest nienullowy; w przeciwnym razie zwraca . Innymi słowy:
Jeśli
a
zostanie przekształcone nanull
, wynika?.x
luba?[x]
tonull
.Jeśli
a
ma wartość inną niż null, wynika?.x
luba?[x]
jest taki sam jak wynika.x
luba[x]
, odpowiednio.Uwaga
Jeśli
a.x
luba[x]
rzuci wyjątek, toa?.x
luba?[x]
rzuci ten sam wyjątek w przypadku, gdya
nie jest null. Na przykład, jeślia
jest wystąpieniem tablicy o wartości innej niż null, ax
znajduje się poza granicamia
,a?[x]
zgłosi IndexOutOfRangeException.
Operatory warunkowe o wartości null są zwarciem. Oznacza to, że jeśli jedna operacja w łańcuchu operacji dostępu warunkowego do członka lub elementu zwraca wartość null
, pozostała część łańcucha nie jest wykonywana. W poniższym przykładzie B
nie jest oceniany, jeśli A
ma wartość null
, i C
nie jest oceniany, jeśli A
lub B
mają wartość null
.
A?.B?.Do(C);
A?.B?[C];
Jeśli może mieć wartość null, ale i nie będą mieć wartości null, jeśli nie ma wartości null, wystarczy zastosować operator warunkowy dla wartości null do .
A?.B.C();
W poprzednim przykładzie B
nie jest ewaluowany i C()
nie jest wywoływany, jeśli A
ma wartość null. Jeśli jednak łańcuchowy dostęp do elementów zostanie przerwany, na przykład przez nawiasy, tak jak w przypadku (A?.B).C()
, mechanizm krótkiego spięcia nie zostanie wykorzystany.
W poniższych przykładach pokazano użycie operatorów ?.
i ?[]
.
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}");
}
W poprzednim przykładzie użyto również operatora łączenia dla wartości null??
, aby określić alternatywne wyrażenie do oceny w przypadku, gdy wynikiem operacji warunkowej null jest null
.
Jeśli a.x
lub a[x]
jest typu wartości nie dopuszczającej do wartości null T
, a?.x
lub a?[x]
ma odpowiadający typ wartości dopuszczającej do wartości null T?
. Jeśli potrzebujesz wyrażenia typu T
, zastosuj operator ??
do wyrażenia warunkowego z wartością null, jak pokazano w poniższym przykładzie:
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
W poprzednim przykładzie, jeśli nie używasz operatora ??
, numbers?.Length < 2
przyjmuje wartość false
kiedy numbers
jest null
.
Uwaga
Operator ?.
ocenia swój lewostronny operand nie więcej niż raz, gwarantując, że nie można go zmienić na null
po zweryfikowaniu jako niebędący null.
Począwszy od języka C# 14, przypisanie jest dopuszczalne przy użyciu wyrażenia dostępu warunkowego o wartości null (?.
i ?[]
) w typach referencyjnych. Zobacz na przykład następującą metodę:
person?.FirstName = "Scott";
messages?[5] = "five";
W poprzednim przykładzie pokazano przypisanie do właściwości i indeksowany element w typie odwołania, który może mieć wartość null. Ważnym zachowaniem tego przypisania jest to, że wyrażenie po prawej stronie =
jest oceniane tylko wtedy, gdy wiadomo, że lewa strona nie jest pusta. Na przykład w poniższym kodzie funkcja GenerateNextIndex
jest wywoływana tylko wtedy, gdy tablica values
nie ma wartości null. Jeśli tablica values
ma wartość null, GenerateNextIndex
nie jest wywoływana:
person?.FirstName = "Scott";
messages?[5] = "five";
Innymi słowy, poprzedni kod jest odpowiednikiem następującego kodu za pomocą instrukcji if
do sprawdzenia wartości null.
if (values is not null)
{
values[2] = GenerateNextIndex();
}
Oprócz przypisania, dowolna forma przypisania złożonego, na przykład +=
lub -=
, jest dozwolona. Jednak przyrost (++
) i dekrementacja (--
) nie są dozwolone.
To ulepszenie nie klasyfikuje wyrażenia warunkowego o wartości null jako zmiennej. Nie można go ref
przypisać, nie można też przypisać do zmiennej ref
ani przekazać do metody jako argument ref
lub out
.
Wywołanie bezpiecznego dla wątków delegata
?.
Użyj tego operatora, aby sprawdzić, czy delegat nie jest wartością null i wywołać go w sposób bezpieczny dla wątków (na przykład podczas zgłaszania zdarzenia), jak pokazano w poniższym kodzie:
PropertyChanged?.Invoke(…)
Ten kod jest odpowiednikiem następującego kodu:
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
Powyższy przykład to bezpieczny wątkowo sposób, aby upewnić się, że wywoływany jest tylko obiekt nie-null handler
. Ponieważ wystąpienia delegatów są niezmienne, żaden wątek nie może zmienić obiektu przywoływanego przez zmienną lokalną handler
. W szczególności, jeśli kod wykonywany przez inny wątek wypisuje się z zdarzenia , a staje się przed wywołaniem , obiekt, do którego odwołuje się , pozostaje bez wpływu.
Wyrażenie wywołania ()
Użyj nawiasów (()), aby wywołać metodę albo delegata.
Poniższy kod demonstruje, jak wywołać metodę z lub bez argumentów i wywołać delegata.
Action<int> display = s => Console.WriteLine(s);
List<int> numbers =
[
10,
17
];
display(numbers.Count); // output: 2
numbers.Clear();
display(numbers.Count); // output: 0
Podczas wywoływania konstruktora za pomocą new
operatora również stosuje się nawiasy.
Inne zastosowania ()
Nawiasy służą również do dostosowywania kolejności oceniania operacji w wyrażeniu. Aby uzyskać więcej informacji, zobacz Operatory języka C#.
Wyrażenia rzutowe, które wykonują jawne konwersje typów, również używają nawiasów.
Indeksowanie z operatora końcowego ^
Operatory indeksu i zakresu mogą być używane z typem, który jest przeliczalny. Typ zliczalny to typ, który ma właściwość nazwaną albo int
, albo Count
z dostępnym akcesorem Length
.
Wyrażenia kolekcji bazują na typach zliczalnych również.
Uwaga
Tablice jednowymiarowe są zliczalne. Tablice wielowymiarowe nie są. Operatory ^
i ..
(zakres) nie mogą być używane w tablicach wielowymiarowych.
Operator ^
wskazuje położenie elementu od końca sekwencji. W przypadku sekwencji o długości length
, ^n
wskazuje element z przesunięciem length - n
od początku sekwencji. Na przykład ^1
wskazuje ostatni element sekwencji, a ^length
wskazuje pierwszy element sekwencji.
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 pokazano w poprzednim przykładzie, wyrażenie ^e
jest typu System.Index. W wyrażeniu ^e
, wynik e
musi być niejawnie konwertowalny na int
.
Możesz również użyć operatora ^
razem z operatorem zakresu, aby utworzyć zakres indeksów. Aby uzyskać więcej informacji, zobacz Indeksy i zakresy.
Począwszy od języka C# 13, indeks z operatora końcowego może być używany w inicjatorze obiektów.
Operator zakresu ..
Operator ..
określa początek i koniec zakresu indeksów jako jego operandy. Operand po lewej stronie jest początkiem inkluzywnego zakresu. Operand po prawej stronie jest wyłącznym końcem zakresu. Jeden z operandów może być indeksem od początku lub od końca sekwencji, jak pokazano w poniższym przykładzie:
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 pokazano w poprzednim przykładzie, wyrażenie a..b
jest typu System.Range. W wyrażeniu a..b
, wyniki a
i b
muszą być niejawnie konwertowane na Int32 lub Index.
Ważne
Niejawne konwersje z int
do Index
wyrzucają ArgumentOutOfRangeException gdy wartość jest ujemna.
Aby uzyskać zakres otwarty, można pominąć dowolny z operandów ..
operatora.
jest odpowiednikiem jest odpowiednikiem jest odpowiednikiem
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));
W poniższej tabeli przedstawiono różne sposoby wyrażania zakresów kolekcji:
Wyrażenie operatora zakresu | opis |
---|---|
.. |
Wszystkie wartości w kolekcji. |
..end |
Wartości od początku do end wyłącznie. |
start.. |
Wartości od start włącznie do końca. |
start..end |
Wartości od start łącznie do end wyłącznie. |
^start.. |
Wartości od start aż do końca, licząc od końca. |
..^end |
Wartości od początku do end , liczone wyłącznie od końca. |
start..^end |
Wartości od start , włącznie, do end , wyłącznie, licząc od końca. |
^start..^end |
Wartości od start włącznie do end wyłącznie, licząc od końca. |
W poniższym przykładzie pokazano efekt użycia wszystkich zakresów przedstawionych w poprzedniej tabeli:
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
Aby uzyskać więcej informacji, zobacz Indeksy i zakresy.
Token ..
jest również używany dla elementu spread w wyrażeniu kolekcji.
Przeciążenie operatora
Operatory .
, ()
, ^
, i ..
nie mogą być przeciążone. Operator []
jest również uważany za operator nieprzeciążalny. Użyj indeksatorów do obsługi indeksowania z typami zdefiniowanymi przez użytkownika.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:
Aby uzyskać więcej informacji na temat indeksów i zakresów, zobacz notatkę dotyczącą propozycji funkcji.