成员访问运算符和表达式(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 directive 的示例所示: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

如果数组索引超出数组相应维度的边界,将引发 IndexOutOfRangeExceptionIf 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 ?[]

Null 条件运算符在 C# 6 及更高版本中可用,仅当操作数的计算结果为非 null 时,null 条件运算符才会将成员访问 ?.元素访问 ?[] 运算应用于其操作数;否则,将返回 nullAvailable 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?.xa?[x] 的结果为 nullIf a evaluates to null, the result of a?.x or a?[x] is null.

  • 如果 a 的计算结果为非 null,则 a?.xa?[x] 的结果将分别与 a.xa[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.xa[x] 引发异常,则 a?.xa?[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 数组实例且 xa的边界之外,则 a?[x] 将引发 IndexOutOfRangeExceptionFor 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. 在以下示例中,如果 A 的计算结果为 null,则不会计算 B;如果 AB 的计算结果为 null,则不会计算 CIn 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.

Null 条件成员访问运算符 ?. 也称为 Elvis 运算符。The null-conditional member access operator ?. is also known as the Elvis operator.

线程安全的委托调用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(…);
}

调用表达式 ()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 的结果必须隐式转换为 intIn expression ^e, the result of e must be implicitly convertible to int.

还可以将 ^ 运算符与范围运算符一起使用以创建一个索引范围。You also can 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 中,ab 的结果必须隐式转换为 intIndexIn 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