????????基于委托的異步編程模型是 .NET 早期版本中實現異步操作的一種方式,主要通過?BeginInvoke
?和?EndInvoke
?方法來實現。這種基于委托的異步模式已被?Task
?和?async/await
?模式取代,但在維護舊代碼時仍可能遇到這種模式。
? ? ? ? 委托的方法中:Invoke用于同步調用;? 而BeginInvoke與EndInvoke用于異步調用。
一、具體介紹:
1.1 異步調用BeginInvoke?方法:
調用格式是:BeginInvoke( 委托的參數,AsyncCallback類型的回調函數,一個object對象),? ? ? 該回調函數是在委托完成后自動調用的函數。 object對象是任何一種對象,可以傳遞給委托函數。
? ? ? ? 特點如下:
? ? ? ? a. 主線程調用此函數后,立即返回,不等待調用完成
? ? ? ? b.? 返回?IAsyncResult?用于監視調用狀態. 在EnInvoke中使用該返回值
1.2 EndInvoke?方法:
????????用于獲取異步調用的結果;調用此方法后,如果操作未完成,會阻塞調用線程直到完成。
? ? ? ? 而且:如果委托函數中有exception異常,是在調用EndInvoke時觸發這個異常的。即即使委托執行中有異常,如果后面沒有調用EndInvoke這個異常不會被程序捕獲到。
? ? ? ? 使用方法如下:
? ? ? ? a = delfun.BeginInvoke(....)
? ? ? ? 結果 = delfun.EndInvoke(a).
1.3?回調函數:
????????當異步操作完成時自動調用; 一般在回調函數中調用?EndInvoke得到結果。
?
1.4?IAsyncResult? 對象
? ? ? 屬性:?IsCompleted? ?委托是否完成(包括正常完成、異常完成)
? ? ? ?委托:AsyncDelegate
? ? ? 傳入的參數:?AsyncState,即調用beginInvoke時傳入的最后一個參數,若不試用,可以是null;
二、實際案例如下:
? ? ? ? 本案例包含委托的異步調用、回調函數,得到結果,以及委托的取消。
public partial class BackgroundDemo : Window{delegate int CalculateDelegate(int x, int y, CancellationToken ct);CancellationTokenSource cts = null;public BackgroundDemo(){InitializeComponent(); btnCancel.IsEnabled = false;cts = new CancellationTokenSource();}int CalculateSum(int a, int b, CancellationToken ct){Console.WriteLine("計算開始子線程ID: " + Thread.CurrentThread.ManagedThreadId);for (int i = 0; i < 20; i++){ct.ThrowIfCancellationRequested(); Thread.Sleep(1000);} return a + b;}void CalculationComplete(IAsyncResult result){CalculateDelegate calculate = (CalculateDelegate)result.AsyncState;var arResult = result as AsyncResult;try{int sum = calculate.EndInvoke(result);Console.WriteLine("回調中獲取結果: " + sum + " (線程ID: " + Thread.CurrentThread.ManagedThreadId + ")");}catch(OperationCanceledException ex){Console.WriteLine("回調時發現:任務取消: " + " (線程ID: " + Thread.CurrentThread.ManagedThreadId + ")");}this.Dispatcher.BeginInvoke((Action)delegate{this.btnStart.IsEnabled = true;});Console.WriteLine("------------結束----------------");}private void btnStart_Click(object sender, RoutedEventArgs e){this.btnStart.IsEnabled = false;this.btnCancel.IsEnabled = true;// 如果需要重置,首先取消當前的令牌cts.Cancel();// 然后釋放資源cts.Dispose();// 重新創建 CancellationTokenSourcects = new CancellationTokenSource();this.tbInfo.Text = "開始計算中";Console.WriteLine("------------開始------------");Console.WriteLine("UI線程ID: " + Thread.CurrentThread.ManagedThreadId );CalculateDelegate cal = CalculateSum;cal.BeginInvoke(4, 5,cts.Token, CalculationComplete, cal);}private void btnCancel_Click(object sender, RoutedEventArgs e){this.btnCancel.IsEnabled = false;cts.Cancel();}
}