.NET 2.0 引入 EAP,優於 IAsyncResult 模式,廣泛用於各類非同步操作。支援 EAP 的類別特徵:
MethodNameAsync 方法啟動非同步作業(可有單一呼叫與多重呼叫兩種多載,後者含 userState 參數區分多次呼叫)。MethodNameCompleted 事件通知完成。CancelAsync 或 MethodNameAsyncCancel 取消作業。ProgressChanged 事件回報進度(含 ProgressPercentage 與 UserState)。完美實作 EAP,提供:
RunWorkerAsync(單一呼叫形式)啟動。RunWorkerCompleted 完成事件。CancelAsync 取消。ProgressChanged 進度事件(需設 WorkerReportsProgress = true)。DoWork 事件:實際執行邏輯置於此,達成啟動與執行分離。ReportProgress 方法觸發 ProgressChanged。class BackgroundWorkerDemo {
private BackgroundWorker _bw;
private string _filePath;
public BackgroundWorkerDemo(string filePath) {
_filePath = filePath;
_bw = new BackgroundWorker();
_bw.WorkerReportsProgress = true;
_bw.DoWork += Bw_DoWork;
_bw.ProgressChanged += Bw_ProgressChanged;
_bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
}
public void ReadAsync() {
if (File.Exists(_filePath)) {
Console.WriteLine("Begin read");
_bw.RunWorkerAsync();
} else throw new FileNotFoundException(_filePath);
}
}
private void Bw_DoWork(object sender, DoWorkEventArgs e) {
long length;
using (StreamReader sr = new StreamReader(_filePath)) {
length = sr.ReadToEnd().Length; // 先取得總長度(註:效能可優化)
}
using (StreamReader sr = new StreamReader(_filePath)) {
long onePercent = length / 100;
long pos = 0;
int percent = 0;
while (!sr.EndOfStream) {
sr.Read(); pos++;
while (pos > onePercent * percent) {
((BackgroundWorker)sender).ReportProgress(percent++);
}
}
e.Result = pos; // 傳遞總字元數給 Completed 事件
}
}
private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
Console.WriteLine("Reading: " + e.ProgressPercentage + "%");
}
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null)
Console.WriteLine("Error: " + e.Error.Message);
else if (e.Cancelled)
Console.WriteLine("Work cancelled");
else
Console.WriteLine("Finished. Length: " + e.Result);
}
static void Main() {
Console.Write("Input file path: ");
string path = Console.ReadLine();
new BackgroundWorkerDemo(path).ReadAsync();
Console.ReadLine(); // 阻塞主執行緒等待完成
}
BeginInvoke/EndInvoke 實作 APM 模式與 BackgroundWorker 實作 EAP 結構相似,皆為非同步模式的範本。BackgroundWorker 即可簡單有效完成開發。ReadToEnd)效能不佳,後續可改用 FileStream.Length 或非同步 I/O 優化。