- Операторы доступа к членам и выражения — операторы точки, индексатора и вызова.
- Выражение доступа к члену .
- Оператор индексатора []
- Доступ к массиву
- Доступ к индексатору
- Другие данные об использовании []
- Операторы с условными значениями ?. NULL и ?[]
- Потокобезопасный вызов делегата
- Выражения вызова ()
- Другие данные об использовании ()
- Индекс от конца: оператор ^
- Оператор Range ..
- Возможность перегрузки оператора
- Спецификация языка C#
- См. также
Операторы доступа к членам и выражения — операторы точки, индексатора и вызова.
Для доступа к члену типа используется несколько операторов и выражений. К этим операторам относятся доступ к членам ( . ), доступ к элементу массива или индексатору ( [] ), конечный индекс ( ^ ), диапазон ( .. ), операторы со значением NULL ( ?. и ?[] ) и вызов метода ( () ). К ним относятся операторы доступа к элементам со значением NULL ( ?. ) и доступа к индексатору ( ?[] ).
- . (доступ к члену) : для доступа к члену пространства имен или типа;
- [] (элемент массива или индексатор доступа) : для доступа к элементу массива или индексатору типа;
- ?. и ?[] (null-условные операторы): для выполнения операции доступа члена или элемента только в том случае, если операнд не равен null;
- () (вызов) : для вызова метода или делегата.
- ^ (индекс от конца) : для определения того, что расположение элемента находится в конце последовательности.
- .. (диапазон): для определения диапазона индексов, которые можно использовать для получения диапазона элементов последовательности.
Выражение доступа к члену .
Маркер . используется для обращения к члену пространства имен или типа, как в следующих примерах.
- Используйте . для обращения к пространству имен, вложенному в другое пространство имен, как показано в следующем примере директивы using .
using System.Collections.Generic;
- Используйте . для создания полного имени для обращения к типу в пределах пространства имен, как показано в следующем коде:
System.Collections.Generic.IEnumerable numbers = new int[] < 1, 2, 3 >;
Используйте директиву using , чтобы сделать использование полных имен необязательным.
var constants = new List(); constants.Add(Math.PI); constants.Add(Math.E); Console.WriteLine($" values to show:"); Console.WriteLine(string.Join(", ", constants)); // Output: // 2 values to show: // 3.14159265358979, 2.71828182845905
Можно также использовать . для вызова метода расширения.
Оператор индексатора []
Квадратные скобки, [] , обычно используются для доступа к элементам массива, индексатора или указателя.
Доступ к массиву
В приведенном ниже примере показано, как получить доступ к элементам массива.
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
Если индекс массива выходит за границы соответствующего измерения массива, возникает исключение IndexOutOfRangeException.
Как показано в предыдущем примере, квадратные скобки также используются в объявлении типа массива и для создания экземпляров массива.
Дополнительные сведения см. в руководстве по работе с массивами.
Доступ к индексатору
В приведенном ниже примере используется тип .NET Dictionary для получения доступа к индексатору:
var dict = new Dictionary(); dict["one"] = 1; dict["pi"] = Math.PI; Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Индексаторы позволяют индексировать экземпляры определяемого пользователем типа аналогично индексации массива. В отличие от индексов массива, которые должны быть целым числом, параметры индексатора могут быть объявлены любым типом.
Другие данные об использовании []
Сведения о доступе к элементу указателя см. в разделе, посвященном оператору доступа к элементу указателя [], статьи Операторы, связанные с указателем.
Кроме того, с помощью квадратных скобок можно указывать атрибуты.
[System.Diagnostics.Conditional("DEBUG")] void TraceMethod() <>
Операторы с условными значениями ?. NULL и ?[]
Условный оператор со значением NULL применяет операцию доступа к элементу или доступу к ?[] элементу к своему операнду только в том случае, ?. если этот операнд имеет значение, отличное от 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 , остальная цепочка не выполняется. В следующем примере не вычисляется, B если вычисляет со значением null , и C не вычисляется, если A значение или B равно null A :
Если A может иметь значение NULL, но B и C не будет иметь значение NULL, если A не равно NULL, необходимо применить только условный оператор NULL к A :
В предыдущем примере не вычисляется и C() не вызывается, B если A имеет значение NULL. Однако при прерывании доступа к связанному члену, например, в круглых скобках, как в (A?.B).C() , не происходит сокращенное вычисление.
В следующем примере иллюстрируется использование операторов ?. и ?[] :
double SumNumbers(List setsOfNumbers, int indexOfSetToSum) < return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN; >var sum1 = SumNumbers(null, 0); Console.WriteLine(sum1); // output: NaN var numberSets = new List < 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
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 FullName Name < get; set; >> public class FullName < public string FirstName < get; set; >public string LastName < get; set; >public void Write() < Console.WriteLine($""); > >
В первом из двух приведенных выше примеров также используется оператор объединения со значением NULL ?? , что позволяет указать альтернативное выражение для вычисления в случае, если результат выполнения условной операции NULL — это null .
Если a.x или a[x] имеет тип T значения, не допускающий значение NULL , a?.x или a?[x] имеет соответствующий тип T? значения, допускающий значение NULL. Если требуется выражение типа T , примените оператор объединения со значением NULL ?? к условному выражению NULL, как показано в следующем примере:
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
Если в предыдущем примере оператор ?? не используется, numbers?.Length < 2 вычисляется как false , если numbers имеет значение null .
Оператор ?. вычисляет левый операнд не более одного раза, гарантируя, что его нельзя изменить на null после того, как он пройдет проверку как не имеющий значение NULL.
Null-условный оператор доступа к элементу ?. также называется элвис-оператором.
Потокобезопасный вызов делегата
Используйте оператор ?. для проверки того, что делегат не равен null, и его вызова потокобезопасным способом (например, в том случае, когда вы собираетесь породить событие), как показано в следующем коде:
Этот код эквивалентен следующему коду:
var handler = this.PropertyChanged; if (handler != null)
Предыдущий пример является потокобезопасным способом, обеспечивающим вызов только не null handler . Так как экземпляры делегата являются неизменяемыми, ни один из потоков не может изменить объект, на который ссылается локальная переменная handler . В частности, если код, выполняемый другим потоком, отменяет подписку на событие PropertyChanged и событие PropertyChanged принимает значение null до вызова handler , объект, на который ссылается handler , остается неизменным.
Выражения вызова ()
Используйте скобки, () , чтобы вызвать метод или делегат.
Приведенный ниже пример демонстрирует вызов делегата и метода с аргументами или без них.
Action display = s => Console.WriteLine(s); var numbers = new List(); numbers.Add(10); numbers.Add(17); display(numbers.Count); // output: 2 numbers.Clear(); display(numbers.Count); // output: 0
Круглые скобки также можно использовать при вызове конструктора с оператором new .
Другие данные об использовании ()
Кроме того, с помощью круглых скобок можно настраивать порядок выполнения операций в выражении. Дополнительные сведения см. в разделе Операторы C#.
В выражениях приведения, которые выполняют явные преобразования типов, также используйте круглые скобки.
Индекс от конца: оператор ^
Оператор ^ указывает положение элемента в конце последовательности. Для последовательности длины length ^n указывает на элемент с length — n смещения от начала последовательности. Например, ^1 указывает на последний элемент последовательности, а ^length — на первый элемент последовательности.
int[] xs = new[] < 0, 10, 20, 30, 40 >; int last = xs[^1]; Console.WriteLine(last); // output: 40 var lines = new List < "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
В предыдущем примере выражение ^e имеет тип System.Index. В выражении ^e результат e должен быть неявно преобразован в int .
Можно также использовать оператор ^ с оператором диапазона для создания диапазона индексов. См. сведения в руководстве по диапазонам и индексам.
Оператор Range ..
Оператор .. задает начало и конец диапазона индексов в качестве операндов. Левый операнд является инклюзивным началом диапазона. Правый операнд является эксклюзивным концом диапазона. Любой из операндов может быть индексом от начала или конца последовательности, как показано в следующем примере:
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(IEnumerable xs) => Console.WriteLine(string.Join(" ", xs));
В предыдущем примере выражение a..b имеет тип System.Range. В выражении a..b результаты a и b должны быть неявно преобразованы в Int32 или Index.
Неявные преобразования из int в вызывают Index исключение , ArgumentOutOfRangeException если значение отрицательное.
Можно проигнорировать любой из операндов оператора .. , чтобы получить открытый диапазон:
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(IEnumerable xs) => Console.WriteLine(string.Join(" ", xs));
В следующей таблице показаны различные способы выражения диапазонов коллекций.
Выражение оператора Range | Описание |
---|---|
.. | Все значения в коллекции. |
..end | Значения от начала до исключительно. end |
start.. | Значения от включительно start до конца. |
start..end | Значения от инклюзивного start к исключительному end . |
^start.. | Значения от включительно start до конечного подсчета от конца. |
..^end | Значения от начала до исключительного end подсчета с конца. |
start..^end | Значения от start инклюзивности до end исключительного подсчета с конца. |
^start..^end | Значения от start инклюзивности до end исключительно обоих, отсчитывающихся от конца. |
В следующем примере показан эффект использования всех диапазонов, представленных в предыдущей таблице:
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($":\t"); // 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
Возможность перегрузки оператора
Операторы . , () , ^ и .. нельзя перегрузить. Оператор [] также считается неперегружаемым. Используйте индексаторы для поддержки индексирования с помощью определяемых пользователем типов.
Спецификация языка C#
Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:
См. сведения о индексах и диапазонах в примечании к функциям.