随着移动设备的普及,异步编程成为了开发者必须掌握的技能之一。幸运的是,如果是一名.NET开发者,可以利用现有的技能和语言,针对一些最受欢迎的移动操作系统进行开发。Windows Phone7是由微软开发的移动操作系统,它是Windows Mobile平台的继任者。
.NET框架提供了多种异步编程模型,可以使用以下任一模型来向客户端代码公开异步特性:
IAsyncResult自.NET1.0以来就已经存在,并在大多数BCL类中使用。EAP的主要优点是它与Visual Studio UI设计器集成。可以通过MSDN上的优秀文章学习如何正确实现IAsyncResult接口(APM):,作者Jeffrey Richter。
在本文中,将展示如何在Windows Phone7上使用实现IAsyncResult接口的类型是多么容易。将使用PowerThreading库,因为它提供了类似于(甚至可以说是改进了)原始MSDN文章中描述的实现。将解释如何使用它以及如何使用AsyncEnumerator类使其变得更容易。
上述代码用于演示。这段代码进行了I/O操作,导致线程阻塞。
public interface IWebService
{
IStockQuote FetchStockQuotes();
}
internal sealed class WebService : IWebService
{
private readonly IStockQuote m_quotes;
public WebService(IStockQuote quotes)
{
m_quotes = quotes;
}
public IStockQuote FetchStockQuotes()
{
Thread.Sleep(50); // 模拟耗时任务
return m_quotes;
}
}
下面的代码展示了ExecuteWithSyncIO方法的实现。应用程序向用户显示一个消息框,表明UI将在执行过程中暂停。
private void ExecuteWithSyncIO()
{
for (Int32 n = 0; n < c_iterations; n++)
{
m_webService.GetStockQuotes();
}
SetStatus("Sync/IO completed.", StatusState.Ready);
}
下面的代码展示了ExecuteWithDelegateBeginInvoke方法的实现。这个方法只是为了演示,因为在Compact Framework中不允许异步调用委托。
private void ExecuteWithDelegateBeginInvoke()
{
Func stockQuoteDelegate = m_webService.GetStockQuotes;
stockQuoteDelegate.BeginInvoke((ar) => {
stockQuoteDelegate.EndInvoke(ar);
}, null);
}
Wintellect.Threading.AsyncProgModel.AsyncResult<TResult>类包含了IAsyncResult接口的实现。这个类型是泛型的,可以轻松地在WebService类上使用它。
using System;
using System.Threading;
using Wintellect.Threading.AsyncProgModel;
public interface IWebService
{
IStockQuote FetchStockQuotes();
}
internal sealed class WebService : IWebService
{
private readonly IStockQuote m_quotes;
public WebService(IStockQuote quotes)
{
m_quotes = quotes;
}
public IAsyncResult BeginGetStockQuotes(AsyncCallback callback, Object state)
{
AsyncResult ar = new AsyncResult(callback, state);
ThreadPool.QueueUserWorkItem(GetStockQuotesHelper, ar);
return ar;
}
public IStockQuote EndGetStockQuotes(IAsyncResult asyncResult)
{
AsyncResult ar = (AsyncResult)asyncResult;
return ar.EndInvoke();
}
private void GetStockQuotesHelper(Object state)
{
AsyncResult ar = (AsyncResult)state;
try
{
IStockQuote quotes = FetchStockQuotes();
ar.SetAsCompleted(quotes, false);
}
catch (Exception e)
{
ar.SetAsCompleted(e, false);
}
}
public IStockQuote FetchStockQuotes()
{
Thread.Sleep(5); // 模拟耗时任务
return m_quotes;
}
}
下面的代码展示了ExecuteWithIAsyncResult方法的实现。唯一的问题是,使用IAsyncResult时,需要指定一个方法,以便在相应的异步操作完成时调用。这可能导致使用同步构造来避免竞态条件。它还会分割代码流。可以使用匿名方法或Lambda表达式内联回调方法,如下所示,但如果逻辑很复杂,代码就不会很漂亮。
private void ExecuteWithIAsyncResult()
{
SetStatus("Working..", StatusState.Busy);
for (Int32 n = 0; n < c_iterations; n++)
{
m_webService.BeginGetStockQuotes((ar) => {
if (Interlocked.Increment(ref m_numDone) == c_iterations)
{
Execute.OnUIThread(() => {
SetStatus("IAsyncResult APM completed.", StatusState.Ready);
});
}
}, null);
}
}
下面的代码展示了ExecuteWithAsyncEnumerator方法的实现。正如看到的,这个方法使代码看起来像是同步执行的,但实际上它是异步执行的。不需要将代码分割成回调方法或内联委托。不需要使用Dispatcher或SynchronizationContext在UI线程中进行调用。所有这些工作都由AsyncEnumerator类处理。
private IEnumerator ExecuteWithAsyncEnumerator(AsyncEnumerator ae)
{
for (Int32 n = 0; n < c_iterations; n++)
{
m_webService.BeginGetStockQuotes(ae.End(), null);
}
ae.SyncContext = null;
yield return c_iterations;
for (Int32 n = 0; n < c_iterations; n++)
{
m_webService.EndGetStockQuotes(ae.DequeueAsyncResult());
}
SetStatus("AsyncEnumerator completed.", StatusState.Ready);
}