GetEnumerator 在 C# 9 開始,能以擴充方法的形式存在。
環境
Visual Studio 2019 - 16.8.0 Preview 3.2
.NET 5.0.0-rc.1.20451.14
Visual Studio 2019 - 16.8.0 Preview 3.2
.NET 5.0.0-rc.1.20451.14
以往在 C# 中如果一個型別要具備迭代器的功能必須要實作 GetEnumerator 方法, 而且這個方法必須是執行個體方法。 C# 9 對此做了一個改變,GetEnumerator 方法可以是擴充方法 (extension method)。
比方說我們為 int 建立一個 GetEnumerator<T>的 extension :
public static class IntExtensions
{
public static IEnumerator<int> GetEnumerator(this int max)
{
return Enumerable.Range(0, max).GetEnumerator();
}
}
然後就可以很奇妙地這樣使用:
foreach (int i in 10)
{
Console.WriteLine(i);
}
這讓事情變得很有趣,比方我可以寫一個自己的集合 (只是個範例,內容並沒有太完整),這個集合不實作任何相關的介面:
public class MyCollection<T>
{
private T[] _data;
private int _count;
public int Capacity => _data.Length;
public int Count => _count;
public T this[int index]
{
get { return _data[index]; }
set
{
if (index == _count || index < 0) throw new IndexOutOfRangeException();
_data[index] = value;
}
}
public MyCollection() : this(4)
{
}
public MyCollection(int capacity)
{
_count = 0;
CreateArray(capacity);
}
private void CreateArray(int capacity)
{
_data = new T[capacity];
}
public void Add(T obj)
{
if (_count == _data.Length)
{
var source = _data;
CreateArray(_data.Length * 2);
Array.Copy(source, _data, source.Length);
}
_data[_count] = obj;
_count++;
}
}
理所當然這個自訂集合是沒法迭代的,因為沒有撰寫任何 GetEnumerator 的執行個體方法,接著就加上一個擴充方法:
public static class MyCollectionExtension
{
public static IEnumerator<T> GetEnumerator<T>(this MyCollection<T> source)
{
for (int i = 0; i < source.Count; i++)
{
yield return source[i];
}
}
}
這樣,MyCollection<T> 就能支援迭代了。
static void Main(string[] args)
{
var collection = new MyCollection<string>();
collection.Add("A");
collection.Add("B");
collection.Add("C");
collection.Add("D");
collection.Add("E");
collection.Add("F");
collection.Add("G");
collection.Add("H");
collection.Add("I");
collection.Add("J");
foreach (var item in collection)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
我們也可以拿 Range struct 來玩玩看:
class Program
{
static void Main(string[] args)
{
foreach (var item in 2..11)
{
Console.WriteLine(item);
}
}
}
public static class RangeExtension
{
public static IEnumerator<int> GetEnumerator(this Range range)
{
for (int i = range.Start.Value; i < range.End.Value; i++)
{
yield return i;
}
}
}