您可以使用數個運算子和表示式來存取類型成員。 成員存取運算子包括成員存取(.
)、陣列元素或索引器存取([]
)、從結尾索引(^
)、範圍(..
)、空條件運算子(?.
和 ?[]
)和方法呼叫(()
)。 這些運算子包括 null 條件式 成員存取(?.
),和索引器存取(?[]
)運算子。
-
.
(成員存取):存取命名空間或型別的成員 -
[]
(陣列元素或索引器存取):存取陣列元素或類型索引器 -
?.
和?[]
(null 條件運算符):只有在運算元不是 null 時,才執行成員或元素存取操作 -
()
(調用):呼叫存取的方法或叫用委派 -
^
(從結尾的索引): 指的是元素位置來自序列的結尾 -
..
(range):指定可用來取得序列元素範圍的索引範圍
成員存取表達式 .
.
您使用 token 來存取命名空間或類型的成員,如下列範例所示:
- 使用
.
來存取命名空間中的巢狀命名空間,如下列using
指令範例所示:
using System.Collections.Generic;
- 使用
.
來形成 限定名稱 來存取命名空間內的類型,如下列程式代碼所示:
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];
using
使用指令來使使用限定名稱成為可選項。
- 使用
.
來存取 類型成員、靜態和非靜態,如下列程式代碼所示:
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
您也可以使用 .
來存取 擴充方法。
索引器運算子 []
方括弧 []
、 通常用於陣列、索引器或指標元素存取。 從 C# 12 開始,[]
用來括住 集合運算式。
陣組存取
下列範例示範如何存取陣列元素:
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<TKey,TValue> 類型來示範索引器存取:
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
索引器可讓您以與數位件索引編製類似的方式,為使用者定義型別的實例編製索引。 與必須是整數的陣列索引不同,索引器參數可以宣告為任何類型。
如需索引器的詳細資訊,請參閱 索引器。
[] 的其他用法
如需指標元素存取的相關信息,請參閱指標相關運算符一文的 Pointer 元素存取運算子 [] 區段。 如需集合表達式的相關信息,請參閱 集合表達式 一文。
您也可以使用方括弧來指定 屬性:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
此外,方括弧可用來指定用於模式比對或測試 的清單模式 。
arr is ([1, 2, ..])
//Specifies that an array starts with (1, 2)
空值條件運算子 ?.
和 ?[]
Null 條件運算子只有在運算元評估為非 Null 時,才會將成員存取作業或?.
作業套用至其運算元,否則返回。 換句話說:
如果
a
評估為null
,則a?.x
或a?[x]
的結果為null
。如果
a
評估為非空,則a?.x
或a?[x]
的結果分別與a.x
或a[x]
的結果相同。備註
如果
a.x
或a[x]
擲回例外狀況,a?.x
或a?[x]
會針對非 Nulla
擲回相同的例外狀況。 例如,如果a
是非 Null 陣列實例,且x
超出 界限a
,a?[x]
則會擲回 IndexOutOfRangeException。
空值條件運算子是短路運算子。 換句話說,如果條件式成員或項目存取作業鏈結中的一個作業傳回 null
,則鏈結的其餘部分不會執行。 在下列範例中,如果 B
被評估為 A
,則 null
不會被評估;如果 C
或 A
被評估為 B
,則 null
不會被評估。
A?.B?.Do(C);
A?.B?[C];
如果 A
可能為 Null,而 B
和 C
不會為 Null(前提是 A 不是 Null),那麼您只需要對 A
使用 Null 條件運算子。
A?.B.C();
在上述範例中, B
不會評估 , C()
如果 A
為 null,則不會呼叫 。 不過,如果鏈結的成員存取遭到中斷,例如有括弧(如 (A?.B).C()
),則不會發生短路。
下列範例示範 ?.
和 ?[]
運算符的使用方式:
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}");
}
第一個上述範例也會使用 null 聯合運算符 ??
來指定替代表達式,以在 Null 條件運算的結果為 null
的情況下進行評估。
如果 a.x
或 a[x]
是不可為 Null 的值類型 T
,那麼 a?.x
或 a?[x]
就是對應的 可為 Null 的值類型T?
。 如果您需要 類型的 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([])); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([3, 4, 5])); // output: 7
在上述範例中,如果您不使用 ??
運算符,當 numbers?.Length < 2
是 false
時,numbers
則評估為 null
。
備註
運算子 ?.
最多只會評估其左側運算元一次,保證在驗證為非 Null 後,不會變成 null
。
從 C# 14 開始,參考型別上允許使用 Null 條件式存取表示式(?.
和 ?[]
)進行指派運算。 例如,請參閱下列方法:
person?.FirstName = "Scott";
messages?[5] = "five";
上述範例顯示對屬性和可能為 null 的參考型別上的索引元素的指派。 此作業的一個重要行為是,只有在已知左側為非空時,才會評估右側的 =
表達式。 例如,在下列程式代碼中,只有在陣列不是 Null 時,函式 GenerateNextIndex
才會被呼叫。
values
如果陣列為 null,GenerateNextIndex
則不會呼叫:
person?.FirstName = "Scott";
messages?[5] = "five";
換句話說,上述程式代碼相當於使用 if
null 檢查語句的下列程式代碼:
if (values is not null)
{
values[2] = GenerateNextIndex();
}
除了指派之外,允許任何形式的 複合指派,例如 +=
或 -=
。 不過,不允許遞增 (++
) 和遞減 (--
) 。
這項增強功能不會將 Null 條件表達式分類為變數。 它無法ref
指派,也無法將它指派給ref
變數,或以 或 ref
自變數的形式傳遞至方法out
。
安全線程委派調用
使用 ?.
運算符來檢查委派是否為非 null,並以執行緒安全的方式叫用它(例如,當您引發事件時),如下程式碼所示:
PropertyChanged?.Invoke(…)
該程式代碼相當於下列程式代碼:
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
上述範例是一種執行緒安全的方式,可確保只叫用非空的handler
。 因為委派實例是不可變的,所以沒有線程可以變更局部變數所 handler
參考的物件。 特別是,如果由另一個線程執行的程式碼取消訂閱PropertyChanged
事件,並且在PropertyChanged
被叫用之前null
已變為handler
時,該handler
所參考的物件將保持不受影響。
呼叫表示式 ()
下列程式代碼示範如何呼叫方法、具有或不含自變數,以及叫用委派:
Action<int> display = s => Console.WriteLine(s);
List<int> numbers =
[
10,
17
];
display(numbers.Count); // output: 2
numbers.Clear();
display(numbers.Count); // output: 0
當您使用運算符叫用建new
函式時,也會使用括弧。
() 的其他使用方式
您也可以使用括號來調整表達式中評估作業的順序。 如需詳細資訊,請參閱 C# 運算子。
轉換表達式會執行明確的類型轉換,也會使用括號。
結束運算子 ^ 的索引
索引和範圍運算元可以搭配可數的類型使用。
可計數的類型是一種類型,其int
包含一個屬性,該屬性的名稱是Count
或Length
,並具有可存取的get
存取子。
集合表達式 也依賴 可計算 的類型。
備註
單一維度陣列 是可計算的。 多維度陣列不是。
^
和 ..
(range) 運算子不能用於多維度陣列。
^
運算子會標示序列中某元素從結尾算起的位置。 針對長度為 length
的序列,^n
指向從序列開頭偏移 length - n
的元素。 例如, ^1
指向序列的最後一個專案,並 ^length
指向序列的第一個專案。
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
如上述範例所示,expression ^e
為 System.Index 類型。 在運算式 ^e
中,的結果 e
必須隱含轉換成 int
。
您也可以使用^
搭配範圍運算子來建立索引範圍。 如需詳細資訊,請參閱 索引和範圍。
從 C# 13 開始,end 運算子的 Index 可用於物件初始化運算式中。
範圍運算子 ..
運算子 ..
會將索引範圍的開始和結尾指定為其作數。 左側作數是範圍的 內含 開始。 右側作數是範圍的 獨佔 結尾。 其中一個運算元可以作為序列開頭或結尾的索引,如下列範例所示:
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));
如上述範例所示,expression a..b
為 System.Range 類型。 在表示式a..b
中,和 a
的結果b
必須隱含轉換成 Int32 或 Index。
這很重要
當值為負數時,從 隱含轉換 int
至 Index
擲回 ArgumentOutOfRangeException 。
您可以省略運算子的任何作數 ..
,以取得開放式範圍:
-
a..
相當於a..^0
-
..b
相當於0..b
-
..
相當於0..^0
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));
下表顯示各種表達集合範圍的方式:
範圍運算子表達式 | 說明 |
---|---|
.. |
集合中的所有值。 |
..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($"{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
如需詳細資訊,請參閱 索引和範圍。
標記 ..
也用於集合表示式中的 散佈專案 。
運算子多載性
.
、()
、 ^
和 ..
運算子無法多載。 運算子 []
也會被視為不可多載的運算符。 使用 索引器 來支援具有使用者定義型別的索引編製。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節:
如需索引和範圍的詳細資訊,請參閱 功能提案附註。