.NET Framework 為異步操作提供了兩種設計模式:使用 IAsyncResult 對象的異步操作與使用事件的異步操作。先來學習前者
概述
IAsyncResult 異步設計模式通過名為 BeginOperationName 和 EndOperationName 的兩個方法來實現原同步方法的異步調用,如 FileStream 類提供了 BeginRead 和 EndRead 方法來從文件異步讀取字節,它們是 Read 方法的異步版本
Begin 方法包含同步方法簽名中的任何參數,此外還包含另外兩個參數:一個AsyncCallback 委托和一個用戶定義的狀態對象。委托用來調用回調方法,狀態對象是用來向回調方法傳遞狀態信息。該方法返回一個實現 IAsyncResult 接口的對象
End 方法用於結束異步操作並返回結果,因此包含同步方法簽名中的 ref 和 out 參數,返回值類型也與同步方法相同。該方法還包括一個 IAsyncResult 參數,用於獲取異步操作是否完成的信息,當然在使用時就必須傳入對應的 Begin 方法返回的對象實例
開始異步操作後如果要阻止應用程序,可以直接調用 End 方法,這會阻止應用程序直到異步操作完成後再繼續執行。也可以使用 IAsyncResult的 AsyncWaitHandle屬性,調用其中的WaitOne等方法來阻塞線程。這兩種方法的區別不大,只是前者必須一直等待而後者可以設置等待超時
如果不阻止應用程序,則可以通過輪循 IAsyncResult的 IsCompleted狀態來判斷操作是否完成,或使用 AsyncCallback 委托來結束異步操作。AsyncCallback 委托包含一個 IAsyncResult的簽名,回調方法內部再調用 End 方法來獲取操作執行結果
嘗試
先來熟悉一下今天的主角,IAsyncResult 接口
1 2 3 4 5 6 7
public
interface
IAsyncResult
{
object
AsyncState {
get
; }
WaitHandle AsyncWaitHandle {
get
; }
bool
CompletedSynchronously {
get
; }
bool
IsCompleted {
get
; }
}
我用一個 AsyncDemo 類作為異步方法的提供者,後面的程序都會調用它。內部很簡單,構造函數接收一個字符串作為 name ,Run 方法輸出 "My name is " + name ,而異步方法直接用委托的 BeginInvoke 和 EndInvoke 方法實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57public
class
AsyncDemo
{
// Use in asynchronous methods
private
delegate
string
runDelegate();
private
string
m_Name;
private
runDelegate m_Delegate;
public
AsyncDemo(
string
name)
{
m_Name = name;
m_Delegate =
new
runDelegate(Run);
}
/**/
/// <summary>
/// Synchronous method
/// </summary>
/// <returns></returns>
public
string
Run()
{
return
"My name is "
+ m_Name;
}
/**/
/// <summary>
/// Asynchronous begin method
/// </summary>
/// <param name="callBack"></param>
/// <param name="stateObject"></param>
/// <returns></returns>
public
IAsyncResult BeginRun(AsyncCallback callBack, Object stateObject)
{
try
{
return
m_Delegate.BeginInvoke(callBack, stateObject);
}
catch
(Exception e)
{
// Hide inside method invoking stack
throw
e;
}
}
/**/
/// <summary>
/// Asynchronous end method
/// </summary>
/// <param name="ar"></param>
/// <returns></returns>
public
string
EndRun(IAsyncResult ar)
{
if
(ar ==
null
)
throw
new
NullReferenceException(
"Arggument ar can't be null"
);
try
{
return
m_Delegate.EndInvoke(ar);
}
catch
(Exception e)
{
// Hide inside method invoking stack
throw
e;
}
}
}
首先是 Begin 之後直接調用 End 方法,當然中間也可以做其他的操作