Операторы и выражения для доступа к элементам (справочник по C#)Member access operators and expressions (C# reference)

При получении доступа к элементу типа можно использовать следующие операторы и выражения:You can use the following operators and expressions when you access a type member:

Выражение доступа к членуMember access expression .

Маркер . используется для обращения к члену пространства имен или типа, как в следующих примерах.You use the . token to access a member of a namespace or a type, as the following examples demonstrate:

  • Используйте . для обращения к пространству имен, вложенному в другое пространство имен, как показано в следующем примере директивы using.Use . to access a nested namespace within a namespace, as the following example of a using directive shows:

    using System.Collections.Generic;
    
  • Используйте . для создания полного имени для обращения к типу в пределах пространства имен, как показано в следующем коде: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 };
    

    Используйте директиву using, чтобы сделать использование полных имен необязательным.Use a using directive to make the use of qualified names optional.

  • Используйте . для обращения к членам типов (статическим и нестатическим), как показано в следующем коде: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
    

Можно также использовать . для вызова метода расширения.You can also use . to access an extension method.

Оператор индексатора []Indexer operator []

Квадратные скобки, [], обычно используются для доступа к элементам массива, индексатора или указателя.Square brackets, [], are typically used for array, indexer, or pointer element access.

Доступ к массивуArray access

В приведенном ниже примере показано, как получить доступ к элементам массива.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

Если индекс массива выходит за границы соответствующего измерения массива, возникает исключение IndexOutOfRangeException.If an array index is outside the bounds of the corresponding dimension of an array, an IndexOutOfRangeException is thrown.

Как показано в предыдущем примере, квадратные скобки также используются в объявлении типа массива и для создания экземпляров массива.As the preceding example shows, you also use square brackets when you declare an array type or instantiate an array instance.

Дополнительные сведения см. в руководстве по работе с массивами.For more information about arrays, see Arrays.

Доступ к индексаторуIndexer access

В приведенном ниже примере используется тип .NET Dictionary<TKey,TValue> для получения доступа к индексатору: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

Индексаторы позволяют индексировать экземпляры определяемого пользователем типа аналогично индексации массива.Indexers allow you to index instances of a user-defined type in the similar way as array indexing. В отличие от индексов массива, которые должны быть целым числом, параметры индексатора могут быть объявлены любым типом.Unlike array indices, which must be integer, the indexer parameters can be declared to be of any type.

Дополнительные сведения см. в руководстве по работе с индексаторами.For more information about indexers, see Indexers.

Другие данные об использовании []Other usages of []

Сведения о доступе к элементу указателя см. в разделе, посвященном оператору доступа к элементу указателя [], статьи Операторы, связанные с указателем.For information about pointer element access, see the Pointer element access operator [] section of the Pointer related operators article.

Кроме того, с помощью квадратных скобок можно указывать атрибуты.You also use square brackets to specify attributes:

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

NULL-условные операторы: ?.Null-conditional operators ?. и ?[]and ?[]

В C# 6 и более поздних версий доступен оператор с условием null, который применяется для доступа к членам, ?., или доступа к элементам, ?[], к операнду только в том случае, если он имеет значение, отличное от NULL, в противном случае он возвращает null.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. Это означает следующее:That is,

  • Если a вычисляется как null, то результатом a?.x или a?[x] является null.If a evaluates to null, the result of a?.x or a?[x] is null.

  • Если a принимает значение, отличное от NULL, результат a?.x или a?[x] совпадает с результатом a.x или a[x]соответственно.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.

    Примечание

    Если a.x или a[x] вызывает исключение, a?.x или a?[x] вызовут то же исключение для отличного от NULL a.If a.x or a[x] throws an exception, a?.x or a?[x] would throw the same exception for non-null a. Например, если a является экземпляром массива, не равным null, и x находится вне границ a, a?[x] вызовет IndexOutOfRangeException.For example, if a is a non-null array instance and x is outside the bounds of a, a?[x] would throw an IndexOutOfRangeException.

Операторы с условием NULL предусматривают сокращенную обработку.The null-conditional operators are short-circuiting. То есть, если в цепочке операций условного доступа к элементу или члену одна из операций возвращает значение null, остальная цепочка не выполняется.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. В следующем примере B не вычисляется, если A принимает значение null, и C не вычисляется, если A или B принимает значение null.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];

В следующем примере иллюстрируется использование операторов ?. и ?[].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

В предыдущем примере также используется оператор объединения со значением NULL ??, чтобы указать альтернативное выражение для вычисления в случае, если результат выполнения условной операции NULL — это null.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.

Если a.x или a[x] является типом T, не допускающим значение NULL, a?.x или a?[x] является соответствующим типом T?, допускающим значение NULL.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?. Если требуется выражение типа T, примените оператор объединения со значением NULL ?? к условному выражению NULL, как показано в следующем примере: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

Если в предыдущем примере оператор ?? не используется, numbers?.Length < 2 вычисляется как false, если numbers имеет значение null.In the preceding example, if you don't use the ?? operator, numbers?.Length < 2 evaluates to false when numbers is null.

Null-условный оператор доступа к элементу ?. также называется элвис-оператором.The null-conditional member access operator ?. is also known as the Elvis operator.

Примечание

В C# 8 оператор, допускающий значение NULL, завершает список предыдущих условных операций со значением NULL.In C# 8, the null-forgiving operator terminates the list of preceding null-conditional operations. Например, выражение x?.y!.z анализируется как (x?.y)!.z.For example, the expression x?.y!.z is parsed as (x?.y)!.z. Из-за этой интерпретации z вычисляется, даже если x — null, что может привести к NullReferenceException.Due to this interpretation, z is evaluated even if x is null, which may result in a NullReferenceException.

Потокобезопасный вызов делегатаThread-safe delegate invocation

Используйте оператор ?. для проверки того, что делегат не равен null, и его вызова потокобезопасным способом (например, в том случае, когда вы собираетесь породить событие), как показано в следующем коде: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(…)

Этот код эквивалентен следующему коду, который будет использоваться в C# 5 или более ранней версии: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(…);
}

Этот потокобезопасный способ гарантирует, что вызывается только handler, не имеющий значения NULL.That is a thread-safe way to ensure that only a non-null handler is invoked. Так как экземпляры делегата являются неизменяемыми, ни один из потоков не может изменить объект, на который ссылается локальная переменная handler.Because delegate instances are immutable, no thread can change the object referenced by the handler local variable. В частности, если код, выполняемый другим потоком, отменяет подписку на событие PropertyChanged и событие PropertyChanged принимает значение null до вызова handler, объект, на который ссылается handler, остается неизменным.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. Оператор ?. вычисляет левый операнд не более одного раза, гарантируя, что его нельзя изменить на null после того, как он пройдет проверку как не имеющий значение NULL.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.

Выражения вызова ()Invocation expression ()

Используйте скобки, (), чтобы вызвать метод или делегат.Use parentheses, (), to call a method or invoke a delegate.

Приведенный ниже пример демонстрирует вызов делегата и метода с аргументами или без них.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

Круглые скобки также можно использовать при вызове конструктора с оператором new.You also use parentheses when you invoke a constructor with the new operator.

Другие данные об использовании ()Other usages of ()

Кроме того, с помощью круглых скобок можно настраивать порядок выполнения операций в выражении.You also use parentheses to adjust the order in which to evaluate operations in an expression. Дополнительные сведения см. в разделе Операторы C#.For more information, see C# operators.

В выражениях приведения, которые выполняют явные преобразования типов, также используйте круглые скобки.Cast expressions, which perform explicit type conversions, also use parentheses.

Индекс от конца: оператор ^Index from end operator ^

Оператор ^, доступный в C# 8.0 и последующих версиях, определяет расположение элемента от конца последовательности.Available in C# 8.0 and later, the ^ operator indicates the element position from the end of a sequence. Для последовательности длины length``^n указывает на элемент с length - n смещения от начала последовательности.For a sequence of length length, ^n points to the element with offset length - n from the start of a sequence. Например, ^1 указывает на последний элемент последовательности, а ^length — на первый элемент последовательности.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

В предыдущем примере выражение ^e имеет тип System.Index.As the preceding example shows, expression ^e is of the System.Index type. В выражении ^e результат e должен быть неявно преобразован в int.In expression ^e, the result of e must be implicitly convertible to int.

Можно также использовать оператор ^ с оператором диапазона для создания диапазона индексов.You can also use the ^ operator with the range operator to create a range of indices. См. сведения в руководстве по диапазонам и индексам.For more information, see Indices and ranges.

Диапазон: оператор .Range operator ..

Оператор диапазона .., доступный в C# 8.0 и последующих версиях, определяет начало и конец диапазона индексов в качестве своих операндов.Available in C# 8.0 and later, the .. operator specifies the start and end of a range of indices as its operands. Левый операнд является инклюзивным началом диапазона.The left-hand operand is an inclusive start of a range. Правый операнд является эксклюзивным концом диапазона.The right-hand operand is an exclusive end of a range. Любой из операндов может быть индексом от начала или конца последовательности, как показано в следующем примере: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));

В предыдущем примере выражение a..b имеет тип System.Range.As the preceding example shows, expression a..b is of the System.Range type. В выражении a..b результаты a и b должны быть неявно преобразованы в int или Index.In expression a..b, the results of a and b must be implicitly convertible to int or Index.

Можно проигнорировать любой из операндов оператора .., чтобы получить открытый диапазон:You can omit any of the operands of the .. operator to obtain an open-ended range:

  • a.. — это эквивалент a..^0a.. is equivalent to a..^0
  • ..b — это эквивалент 0..b..b is equivalent to 0..b
  • .. — это эквивалент 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));

См. сведения в руководстве по диапазонам и индексам.For more information, see Indices and ranges.

Возможность перегрузки оператораOperator overloadability

Операторы ., (), ^ и .. перегрузить нельзя.The ., (), ^, and .. operators cannot be overloaded. Оператор [] также считается неперегружаемым.The [] operator is also considered a non-overloadable operator. Используйте индексаторы для поддержки индексирования с помощью определяемых пользователем типов.Use indexers to support indexing with user-defined types.

Спецификация языка C#C# language specification

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:For more information, see the following sections of the C# language specification:

См. сведения о индексах и диапазонах в примечании к функциям.For more information about indices and ranges, see the feature proposal note.

См. такжеSee also