前篇介紹完 Index,該是讓 Range 登場的時候。
本篇文章使用環境
開發環境 Visual Studio 2019 Preview 1 (16.0.0 Preview 1)
框架 .NET Core 3.0.0-preview-27122-01
編譯器 C# 8.0 beta
開發環境 Visual Studio 2019 Preview 1 (16.0.0 Preview 1)
框架 .NET Core 3.0.0-preview-27122-01
編譯器 C# 8.0 beta
Range structure 和 Index structure (參考前一篇) 有密不可分的關係,從 Range 的公開成員看起:
namespace System
{
public struct Range : IEquatable<Range>
{
public Index End { get; }
public Index Start { get; }
public static Range All();
public static Range Create(Index start, Index end);
public static Range FromStart(Index start);
public static Range ToEnd(Index end);
public override bool Equals(object value);
public bool Equals(Range other);
public override int GetHashCode();
public override string ToString();
}
}
Range 有兩個重要的公開成員屬性,分別是 Start 和 End,從上面的程式碼可以看出來它們的型別都是 Index,這也就是定義了 Range 的範圍值,依據Bill目前的測試來看,Range 的定義為 Start ≦ X <End。
建立 Range 的最基本方式是利用三個靜態的方法:
(1) Create:給予 Start 與 End 的值設定範圍
(2) FromStart:只給 Start 值,表示範圍從 Start 開始直到末端(index ^0)
(3) ToEnd:只給 End 值,表示範圍從開頭(index 0)到 End
(2) FromStart:只給 Start 值,表示範圍從 Start 開始直到末端(index ^0)
(3) ToEnd:只給 End 值,表示範圍從開頭(index 0)到 End
例如:
class Program
{
static void Main(string[] args)
{
Range r1 = Range.Create(1, ^1);
Range r2 = Range.FromStart(1);
Range r3 = Range.ToEnd(3);
Display(r1);
Display(r2);
Display(r3);
Console.ReadLine();
}
static void Display(Range range)
{
Console.WriteLine(range);
}
}
結果會顯示為:
1..^1
1..^0
0..3
1..^0
0..3
C# 8.0 為 Range 也新增了一個運算子 "..", 這兩個點點意思就差不多是"從哪到哪 (form to)"的意思。還是那句老話,懶還要更懶,這個運算子可以快速地建立 Range:
class Program
{
static void Main(string[] args)
{
var array = new string[] { "A", "B", "C", "D", "E", "F", "G" };
var ranges = new List<Range>
{
{..},
{0..^0},
{1..3 },
{1..^1},
{1.. },
{..^2},
};
foreach (var range in ranges)
{
foreach (var s in array[range])
{
Console.Write(s);
}
Console.WriteLine();
}
Console.ReadLine();
}
}
當使用 .. 的時候,代表的就是 0..^0,也就是 Range.All() 的回傳。
1..3 代表的是介於 1~3 之間,但不包含 3 及以後,也就是回傳 "BC"。
1..^1 代表的是介於 1~ 倒數第1個之間,但不包含倒數第1個及以後,所以回傳 "BCDEF"
1.. 代表的是從1 開始直到最後,所以回傳 "BCDEFG"
..^2 代表從起始到倒數第2個,但不包含倒數第2個及以後,所以回傳 "ABCDE"
1..3 代表的是介於 1~3 之間,但不包含 3 及以後,也就是回傳 "BC"。
1..^1 代表的是介於 1~ 倒數第1個之間,但不包含倒數第1個及以後,所以回傳 "BCDEF"
1.. 代表的是從1 開始直到最後,所以回傳 "BCDEFG"
..^2 代表從起始到倒數第2個,但不包含倒數第2個及以後,所以回傳 "ABCDE"
老實說,這以前也不是沒有解法,linq 中有個 Skip - Take 也可以做到類似的效果,例如:
class Program
{
static void Main(string[] args)
{
var array = new string[] { "A", "B", "C", "D", "E", "F", "G" };
var ranges = new List<ValueTuple<int, int>>
{
(0, array.Length),
(0, array.Length),
(1, 2),
(1, array.Length -2),
(1, array.Length -1),
(0, array.Length -2)
};
foreach (var range in ranges)
{
foreach (var s in array.Skip(range.Item1).Take(range.Item2))
{
Console.Write(s);
}
Console.WriteLine();
}
Console.ReadLine();
}
}
這兩種用法其實相輔相成,如果資訊上的條件比較適合的是『從A索引到B索引的範圍』,那 Range 會比較直覺;如果條件比較適用於『跳過幾筆取得幾筆』的情境,那 Skip - Take 會比較順手。
Ranges and Indices 的 Sample 可以參考我的 github:RangesAndIndicesSamples