要客製化類別,使其具有迭代器能力,在 C# 中,我們僅需要實作
IEnumerable<T>
這個介面,在您的類別中,實作出 GetEnumerator
這個方法即可。
這裡,我們模擬一個情境,您需要透過網路抓取四個網頁內容,不過,你無法控制哪個網頁會先讀取完畢,因此,您將需要設您的類別,只要網頁內容讀取完成之後,就會回傳到用戶端;而在用戶端中,可以使用 foreach 陳述式來逐一讀取這些網頁內容。為了達到這樣的需求,我們是用 C# 工作的靜態方法
Task.WhenAny
來協助我們處理這樣需求。public class DownloadWeb : IEnumerable<DownloadWeb.GetWebResult>
{
public class GetWebResult
{
public int Length { get; set; }
public string URL { get; set; }
public int ms { get; set; }
}
public string[] Urls = new string[]
{
"https://tw.yahoo.com/",
"http://www.msn.com/zh-tw/",
"https://world.taobao.com/",
"https://www.microsoft.com",
};
public IEnumerator<GetWebResult> GetEnumerator()
{
List<Task<GetWebResult>> tasks = new List<Task<GetWebResult>>();
tasks.Add(GetWebContent(Urls[0]));
tasks.Add(GetWebContent(Urls[1]));
tasks.Add(GetWebContent(Urls[2]));
tasks.Add(GetWebContent(Urls[3]));
while (tasks.Count > 0)
{
var aTask = Task.WhenAny(tasks);
tasks.Remove(aTask.Result);
var result = aTask.Result;
yield return result.Result;
}
}
public async Task<GetWebResult> GetWebContent(string url)
{
Stopwatch sw = new Stopwatch();
sw.Start();
using (var client = new HttpClient())
{
var result = await client.GetStringAsync(url);
sw.Stop();
GetWebResult getWebResult = new GetWebResult()
{
Length = result.Length,
URL = url,
ms = sw.Elapsed.Milliseconds
};
return getWebResult;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
在我們要進行測試的時候,首先,我們產生出一個
DownloadWeb
物件,使用 foreach
陳述式,逐一取得讀取到的網頁內容。你可以嘗試重複執行這個練習程式,將會發現到,每次進行 foreach 陳述式的時候,回傳結果順序都不進相同。DownloadWeb downloadWeb = new DownloadWeb();
foreach (var item in downloadWeb)
{
Console.WriteLine($"{item.URL} ({item.ms}) : {item.Length}");
}
Console.WriteLine($"Press any key to Exist...{Environment.NewLine}");
Console.ReadKey();
執行結果
http://www.msn.com/zh-tw/ (241) : 46965
https://tw.yahoo.com/ (327) : 201659
https://world.taobao.com/ (349) : 220947
https://www.microsoft.com (4) : 1020
Press any key to Exist...
迭代器 可用來逐步執行集合,例如清單和陣列。迭代器方法或 get 存取子會對集合執行自訂反覆運算
。