說說C# 8.0 新增功能Index和Range的^0是什麼?

前言

  在《C# 8.0 中使用 Index 和 Range》這篇中有人提出^0是什麼意思?處於好奇就去試了,結果拋出異常。查看官方文檔說^0索引與 sequence[sequence.Length] 相同,表達式 sequence[^0] 不會引發異常,就像 sequence[sequence.Length] 一樣。但是在實際使用[^0]的時候拋出IndexOutOfRangeException的異常,很疑惑究竟是什麼原因?

  先說一下 C# 8.0 新增的兩個新類型和兩個新運算符,允許構造System.Index和System.Range對象,並在運行時索引/切片集合。

一、System.Index和System.Range結構

1、Index

  表示一種可用於從開頭或從結尾索引集合的類型。

public struct Index : IEquatable<Index> 

  示例代碼

string [] myArray = new string[5] { "A", "B", "C", "D", "E" };
string  strArray= myArray[^1]; // strArray = E

  代碼中使用末尾運算符^和Index類型,myArray[ ^1] 表示從數組的倒數第一個元素,也就是從末尾開始算的第一個元素,所以最終結果是:E。

  Hat運算符(^)的索引,指定一個索引與序列末尾相關。

2、Range

  表示具有起始索引和結束索引的範圍。

public struct Range : IEquatable<Range>

  示例代碼

string[] myArray = new string[5] { "A", "B", "C", "D", "E" };
string[] strArray = myArray[0..2];         // { A, B }

  代碼中使用範圍運算符(..)和Range類型,myArray[0..2]表示把myArray這個序列,從索引爲0的元素一直找到索引爲2(但不包括索引2)的元素提取出來組成新的數組,所以最終結果是: {A,B} 

  範圍運算符(..),用於指定範圍的開始和末尾,就像操作數一樣。

  Range類型範圍運算符包含start不包含end。eg:myArray[0..2]包含索引0不包含索引2

3、Index和Range組合使用

  嘗試在Range的兩端混合使用"從開始"和"從末尾"的Index,看看會發生什麼?

var strNum = new string[]
{
              // index from start    index from end
    "A",      // 0                   ^9
    "B",      // 1                   ^8
    "C",      // 2                   ^7
    "D",      // 3                   ^6
    "E",      // 4                   ^5
    "F",      // 5                   ^4
    "G",      // 6                   ^3
    "H",      // 7                   ^2
    "I"       // 8                   ^1
};            // 9 (strNum.Length)   ^0
foreach (var item in strNum[0..^1])
    Console.Write($"{item}");
foreach (var item in strNum[1..^0])
    Console.Write($"{item}");
foreach (var item in strNum[0..^0])
    Console.Write($"{item}");

  輸出結果:

ABCDEFGH
BCDEFGHI
ABCDEFGHI

  0..^1 與 ..^1   相同 表示從0索引位置到末尾開始算的第1個元素

  1.. 與 1..^0    相同 表示從1索引位置到末尾開始算的第0個元素

  .. 與  0..^0   相同  表示全部從頭到尾

二、[^0]會拋異常

1、[^1] 示例代碼

int[] myArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int num = myArray[^1];   //num=10

2、[^0]示例代碼

int[] myArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int num = myArray[^0]; //拋異常

  代碼結果如下圖所示:

     

 官方文檔描述:請考慮數組 sequence。 0 索引與 sequence[0] 相同。 ^0 索引與 sequence[sequence.Length] 相同。 表達式 sequence[^0]不會引發異常,就像 sequence[sequence.Length] 一樣。 對於任何數字 n,索引 ^n 與 sequence[sequence.Length - n] 相同。

  通過自己搜索到合理的解釋 Index 類型 從尾部開始的索引是從1開始的,與序列的長度相關,那麼意思就說單獨使用末尾運算符時索引只能從1開始。

三、遺留問題

  使用末尾運算符時索引只能從1開始,但是Index和Range組合使用時可以從0開始,目前還沒有找到具體原因,如果大家有好的解釋和方法,歡迎留言溝通和交流。

四、總結

  1、Range類型  運算符(..)包括Start不包括End

  2、Index類型 末尾運算符(^)

    · 從頭開始的索引是從0開始的

    · 從尾部開始的索引是從1開始的,與序列的長度相關

  3、減少 SubString 的使用,eg:var str="12345"截取後三位,之前寫法str.Substring(2,3),新語法str[^3..]

  4、使用^和..這兩個語法糖,讓代碼更加乾淨,可讀,易維護

 

 優秀是一種習慣,歡迎大家關注學習  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章