本系列第一講第四節,介紹非同步回呼模式避免阻塞 UI,並展示 HttpWebRequest.BeginGetResponse/EndGetResponse 實際應用。
private delegate int MyMethod();
private int LongRunning() { Thread.Sleep(10000); return 100; }
private void Callback(IAsyncResult ar)
{
if (ar == null) return;
var result = ((MyMethod)ar.AsyncState).EndInvoke(ar);
// 跨執行緒更新 UI 需 Invoke (此處簡化)
textBox1.Text = result.ToString();
}
private void btnStart_Click(object sender, EventArgs e)
{
var del = new MyMethod(LongRunning);
del.BeginInvoke(Callback, del); // 立即返回,UI 不阻塞
}
BeginInvoke 最後兩參數:AsyncCallback 與 object state (通常傳委派自身)。Control.Invoke 或 SynchronizationContext。AsyncState 取回傳入的 state 物件。EndInvoke 取得結果或傳播例外,**否則資源洩漏**。
private void DownloadCallback(IAsyncResult ar)
{
if (ar == null) return;
var req = (HttpWebRequest)ar.AsyncState;
try
{
using (var resp = (HttpWebResponse)req.EndGetResponse(ar))
using (var stream = resp.GetResponseStream())
using (var reader = new StreamReader(stream))
{
string html = reader.ReadToEnd();
// UI 更新需 Invoke
this.Invoke((Action)(() => textBox1.Text = html));
}
}
catch (Exception ex)
{
this.Invoke((Action)(() => textBox1.Text = "Error: " + ex.Message));
}
}
private void btnDownload_Click(object sender, EventArgs e)
{
var req = (HttpWebRequest)WebRequest.Create("https://www.example.com");
req.BeginGetResponse(DownloadCallback, req);
}
| 模式 | Begin 方法 | End 方法 | 適用場景 |
|---|---|---|---|
| 委派 | BeginInvoke | EndInvoke | 任意同步方法非同步化 |
| WebRequest | BeginGetResponse | EndGetResponse | HTTP 下載 |
| Stream | BeginRead/Write | EndRead/Write | 檔案/網路流 |
| Socket | BeginSend/Receive | EndSend/Receive | 低層網路通訊 |
APM 回呼模式是 .NET 1.0 時代非同步基石。現代開發請優先使用 async/await (TAP),但理解 APM 有助於維護舊代碼與掌握底層機制。