C#開發中經常需要使用使用異步操作,特別是Windows phone和Silverlight下層的很多IO相關的訪問都是異步的。
標准異步方法一般都是Begin[Invoke]和End[Invoke]的一對方法,用法就不多說了。
我最近在寫用命令模式常用的HttpRequest操作,就想將命令包裝成異步方法,
想了很久使用了下面的方式包裝異步:
首先是常規的異步調用時序:
現在使用包裝使用了2個類一個用於包裝AsyncCallback,一個用於包裝IAsyncResult,來包裝這個時序。
類的代碼如下:
/// <summary>
/// 異步回調代理
/// </summary>
public class AsyncCallbackDelegate
{
/// <summary>
/// 需要代理的異步回調
/// </summary>
private readonly AsyncCallback asyncCallback;
/// <summary>
/// 原始調用對象www.2cto.com
/// </summary>
public object Delegate { get; set; }
public AsyncResultDelegate Result { get; set; }
/// <summary>
/// 構造 異步回調代理
/// </summary>
/// <param name="asyncCallback">需要代理的異步回調</param>
public AsyncCallbackDelegate(AsyncCallback asyncCallback)
{
this.asyncCallback = asyncCallback;
}
/// <summary>
/// 包裝後的異步回調
/// </summary>
/// <param name="asyncResult"></param>
public void AsyncCallBack(IAsyncResult asyncResult)
{
//用AsyncResultDelegate包裝asyncResult
var asyncResultDelegate = new AsyncResultDelegate(asyncResult) { Delegate = Delegate };
asyncCallback(asyncResultDelegate);//調用原始異步回調
}
}
/// <summary>
/// 異步狀態代理
/// </summary>
public class AsyncResultDelegate : IAsyncResult
{
/// <summary>
/// 原始異步狀態
/// </summary>
private readonly IAsyncResult asyncResult;
/// <summary>
/// 原始調用對象
/// </summary>
public object Delegate { get; set; }
public AsyncResultDelegate(IAsyncResult asyncResult)
{
this.asyncResult = asyncResult;
}
#region 裝飾模式包裝
public object AsyncState
{
get { return AsyncResult.AsyncState; }
}
public System.Threading.WaitHandle AsyncWaitHandle
{
get { return AsyncResult.AsyncWaitHandle; }
}
public bool CompletedSynchronously
{
get { return AsyncResult.CompletedSynchronously; }
}
public bool IsCompleted
{
get { return AsyncResult.IsCompleted; }
}
public IAsyncResult AsyncResult
{
get { return asyncResult; }
}
#endregion
}
包裝後的調用時序:
演示代碼AddCommand 用於使用代理包裝異步執行a+b返回結果
public class AddCommand
{
private readonly int a;
private readonly int b;
public AddCommand(int a, int b)
{
this.a = a;
this.b = b;
}
public IAsyncResult BeginInvoke(AsyncCallback asyncCallback, object state)
{
Func<int, int, int> addFunc = (x, y) => x + y;//測試用的原始異步調用對象
AsyncCallback callbackDelegate = asyncCallback;
if (asyncCallback != null)
{
//用AsyncCallbackDelegate包裝AsyncCallback
var tmp = new AsyncCallbackDelegate(asyncCallback) { Delegate = addFunc };
callbackDelegate = tmp.AsyncCallBack;
}
var asyncResult = addFunc.BeginInvoke(a, b, callbackDelegate, state);
//用AsyncResultDelegate包裝asyncResult
return new AsyncResultDelegate(asyncResult) { Delegate = addFunc };
}
public int EndInovke(IAsyncResult result)
{
var asyncResultDelegate = (AsyncResultDelegate)result;//還原AsyncResultDelegate
Func<int, int, int> addFunc = (Func<int, int, int>)asyncResultDelegate.Delegate;//獲得原始對象
return addFunc.EndInvoke(asyncResultDelegate.AsyncResult);//傳入原始AsyncResult
}
}
調用AddCommand 支持2種調用方式
class Program
{
static void Main(string[] args)
{
//主線程等待後調用EndInovke
{
AddCommand invoker = new AddCommand(1, 2);
var async = invoker.BeginInvoke(null, null);
async.AsyncWaitHandle.WaitOne();
int result = invoker.EndInovke(async);
Console.WriteLine(result);
}
//由CallBack調用EndInovke
{
AddCommand invoker = new AddCommand(5, 9);
var async = invoker.BeginInvoke(CallBack, invoker);
async.AsyncWaitHandle.WaitOne();
}
Console.ReadLine();
}
static void CallBack(IAsyncResult asyncResult)
{
AddCommand invoker = asyncResult.AsyncState as AddCommand;
int result = invoker.EndInovke(asyncResult);
Console.WriteLine(result);
}
}