Операторы доступа к членам и выражения — операторы точки, индексатора и вызова.
Статья
Для доступа к члену типа используется несколько операторов и выражений. К этим операторам относятся доступ к члену (.), элемент массива или доступ индексатора ([]), индекс от конца (^), диапазон (..), операторы null-условные (?. и) и ?[]вызов метода (()). К ним относятся операторы доступа к члену с значением NULL и индексатор (?[]).?.
Квадратные скобки, [], обычно используются для доступа к элементам массива, индексатора или указателя. Начиная с C# 12, [] заключает выражение коллекции.
Доступ к массиву
В приведенном ниже примере показано, как получить доступ к элементам массива.
Если индекс массива выходит за границы соответствующего измерения массива, возникает исключение IndexOutOfRangeException.
Как показано в предыдущем примере, квадратные скобки также используются в объявлении типа массива и для создания экземпляров массива.
Дополнительные сведения см. в руководстве по работе с массивами.
Доступ к индексатору
В приведенном ниже примере используется тип .NET Dictionary<TKey,TValue> для получения доступа к индексатору:
C#
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Индексаторы позволяют индексировать экземпляры определяемого пользователем типа аналогично индексации массива. В отличие от индексов массива, которые должны быть целым числом, параметры индексатора могут быть объявлены любым типом.
Оператор с условным значением NULL применяет к операнду операцию доступа к элементу (?.) или доступ к элементу только?[] в том случае, если этот операнд оценивается как ненулевое; в противном случае возвращаетсяnull. Другими словами:
Если a вычисляется как null, то результатом a?.x или a?[x] является null.
Если a принимает значение, отличное от NULL, результат a?.x или a?[x] совпадает с результатом a.x или a[x]соответственно.
Примечание
Если a.x или a[x] вызывает исключение, a?.x или a?[x] вызовут то же исключение для отличного от NULL a. Например, если a является экземпляром массива, не равным null, и x находится вне границ a, a?[x] вызовет IndexOutOfRangeException.
Операторы с условием NULL предусматривают сокращенную обработку. То есть, если в цепочке операций условного доступа к элементу или члену одна из операций возвращает значение null, остальная цепочка не выполняется. В следующем примере не вычисляется, если вычисляется и C не оценивается, если A или B оцениваетсяnull: BAnull
C#
A?.B?.Do(C);
A?.B?[C];
Если значение равно null, C но не будет равно null, если A значение A не равно NULL, необходимо применить только оператор с условным значением NULL кAB:
C#
A?.B.C();
В предыдущем примере B не вычисляется и C() не вызывается, если A значение NULL. Однако при прерывании доступа к связанному члену, например, в круглых скобках, как в (A?.B).C(), не происходит сокращенное вычисление.
В следующем примере иллюстрируется использование операторов ?. и ?[]:
C#
doubleSumNumbers(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: 6var sum3 = SumNumbers(numberSets, 1);
Console.WriteLine(sum3); // output: NaN
C#
namespaceMemberAccessOperators2;
publicstaticclassNullConditionalShortCircuiting
{
publicstaticvoidMain()
{
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
}
}
publicclassPerson
{
public required FullName Name { get; set; }
}
publicclassFullName
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
publicvoidWrite() => Console.WriteLine($"{FirstName}{LastName}");
}
В первом из двух приведенных выше примеров также используется оператор объединения со значением NULL ??, что позволяет указать альтернативное выражение для вычисления в случае, если результат выполнения условной операции NULL — это null.
Если a.x или a[x] является типом T, не допускающим значение NULL, a?.x или a?[x] является соответствующим типом T?, допускающим значение NULL. Если требуется выражение типа T, примените оператор объединения со значением NULL ?? к условному выражению NULL, как показано в следующем примере:
Если в предыдущем примере оператор ?? не используется, numbers?.Length < 2 вычисляется как false, если numbers имеет значение null.
Примечание
Оператор ?. вычисляет левый операнд не более одного раза, гарантируя, что его нельзя изменить на null после того, как он пройдет проверку как не имеющий значение NULL.
Null-условный оператор доступа к элементу ?. также называется элвис-оператором.
Потокобезопасный вызов делегата
Используйте оператор ?. для проверки того, что делегат не равен null, и его вызова потокобезопасным способом (например, в том случае, когда вы собираетесь породить событие), как показано в следующем коде:
C#
PropertyChanged?.Invoke(…)
Этот код эквивалентен следующему коду:
C#
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
Предыдущий пример — это потокобезопасный способ, чтобы убедиться, что вызывается только ненулевое handler значение. Так как экземпляры делегата являются неизменяемыми, ни один из потоков не может изменить объект, на который ссылается локальная переменная handler. В частности, если код, выполняемый другим потоком, отменяет подписку на событие PropertyChanged и событие PropertyChanged принимает значение null до вызова handler, объект, на который ссылается handler, остается неизменным.
Выражения вызова ()
Используйте скобки, (), чтобы вызвать метод или делегат.
Приведенный ниже пример демонстрирует вызов делегата и метода с аргументами или без них.
Круглые скобки также можно использовать при вызове конструктора с оператором new.
Другие данные об использовании ()
Кроме того, с помощью круглых скобок можно настраивать порядок выполнения операций в выражении. Дополнительные сведения см. в разделе Операторы C#.
В выражениях приведения, которые выполняют явные преобразования типов, также используйте круглые скобки.
Индекс от конца: оператор ^
Операторы индекса и диапазона можно использовать с типом, подсчитываемым. Подсчитываемый тип — это тип, имеющий int свойство с именем Count или Length с доступным get методом доступа. Выражения коллекции также зависят от числовых типов.
Оператор ^ указывает позицию элемента из конца последовательности. Для последовательности длины length^n указывает на элемент с length - n смещения от начала последовательности. Например, ^1 указывает на последний элемент последовательности, а ^length — на первый элемент последовательности.
C#
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: threestring word = "Twenty";
Index toFirst = ^word.Length;
char first = word[toFirst];
Console.WriteLine(first); // output: T
В предыдущем примере выражение ^e имеет тип System.Index. В выражении ^e результат e должен быть неявно преобразован в int.
Начиная с C# 13 индекс из конечного оператора можно использовать в инициализаторе объектов.
Оператор range ..
Оператор .. задает начало и конец диапазона индексов в качестве операндов. Левый операнд является инклюзивным началом диапазона. Правый операнд является эксклюзивным концом диапазона. Любой из операндов может быть индексом из начала или с конца последовательности, как показано в следующем примере:
C#
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 30int margin = 1;
int[] inner = numbers[margin..^margin];
Display(inner); // output: 10 20 30 40string line = "one two three";
int amountToTakeFromEnd = 5;
Range endIndices = ^amountToTakeFromEnd..^0;
string end = line[endIndices];
Console.WriteLine(end); // output: threevoid Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
В предыдущем примере выражение a..b имеет тип System.Range. В выражении a..b результаты a и b должны быть неявно преобразованы в Int32 или Index.
Важно!
Неявные преобразования, отбрасываемые в intIndex случае отрицательного ArgumentOutOfRangeException значения.
Можно проигнорировать любой из операндов оператора .., чтобы получить открытый диапазон:
Маркер .. также используется для элемента spread в выражении коллекции.
Возможность перегрузки оператора
Операторы ., ^()и .. операторы не могут быть перегружены. Оператор [] также считается неперегружаемым. Используйте индексаторы для поддержки индексирования с помощью определяемых пользователем типов.
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Отзыв о .NET
.NET — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
Присоединитесь к серии встреч для создания масштабируемых решений искусственного интеллекта на основе реальных вариантов использования с другими разработчиками и экспертами.