這是Windows 8 異步編程的第二部分,為什么分成兩節(jié)呢,因?yàn)椋诙?jié)確實(shí)太讓人興奮了。恰巧有篇Windows 8 開(kāi)發(fā)人員博客也是這樣一個(gè)結(jié)構(gòu),題目是WinRT 和 await,之前看過(guò),沒(méi)有什么感覺(jué),今天試了一下,里面還是有很多需要注意的地方。
參考文獻(xiàn): 1. Windows 8 應(yīng)用程序開(kāi)發(fā)人員博客:深入探究WinRT和await:http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/30/winrt-await.aspx 2. MSDN
因?yàn)槲沂褂玫氖荂++語(yǔ)言,所以我主要是用C++來(lái)編程,C#開(kāi)發(fā)的朋友可以看參考文獻(xiàn)1,以下是我的理解和我覺(jué)得重要的東西。請(qǐng)?jiān)徫矣幸徊糠謨?nèi)容是摘抄自文獻(xiàn)1.
一。 基礎(chǔ)知識(shí)
我也覺(jué)得應(yīng)該從基礎(chǔ)著手,WinRT中的所有異步功能全部源自一個(gè)接口:Windows::Foundation::IAsyncInfo
1 public interface IAsyncInfo
2 {
3 AsyncStatus Status { get; }//只讀
4 HResult ErrorCode { get; }//只讀
5 uint Id { get; }//只讀
6
7 void Cancel();
8 void Close();
9 }
所有的異步操作都應(yīng)該實(shí)現(xiàn)此接口。但是該接口缺少了一個(gè)至關(guān)重要的功能:操作完成之后的回調(diào)函數(shù)。因此就有了下面四個(gè)接口。我想說(shuō),請(qǐng)大家注意每個(gè)新街口中都有一個(gè)Completed的屬性,我們可以設(shè)置這個(gè)屬性所要執(zhí)行的代碼,就是我們的操作完成之后,將要執(zhí)行的代碼。
1 public interface IAsyncAction : IAsyncInfo 2 {
3 AsyncActionCompletedHandler Completed { get; set; }
4 void GetResults();// void,不返回結(jié)果
5 }
6
7 public interface IAsyncOperation<TResult> : IAsyncInfo
8 {
9 AsyncOperationCompletedHandler<TResult> Completed { get; set; }
10 TResult GetResults();//TResult 返回結(jié)果
11 }
12
13 public interface IAsyncActionWithProgress<TProgress> : IAsyncInfo
14 {
15 AsyncActionWithProgressCompletedHandler<TProgress> Completed { get; set; }
16 AsyncActionProgressHandler<TProgress> Progress { get; set; }//有Progress
17 void GetResults();//void,不返回結(jié)果
18 }
19
20 public interface IAsyncOperationWithProgress<TResult, TProgress> : IAsyncInfo
21 {
22 AsyncOperationWithProgressCompletedHandler<TResult, TProgress> Completed { get; set; }
23 AsyncOperationProgressHandler<TResult, TProgress> Progress { get; set; }//有Progress
24 TResult GetResults();//TResult,返回結(jié)果
25 }
暫停,我想說(shuō),C#開(kāi)發(fā)人員真的很幸運(yùn),C++開(kāi)發(fā)人員需要寫(xiě)很久的代碼,C#只要一點(diǎn)點(diǎn)就足夠了。這是我的牢騷,請(qǐng)忽略。
那么我們還是以打開(kāi)文件為例吧,上一篇文章中,我們使用了create_task這個(gè)方法,打開(kāi)了文件,并且將一些內(nèi)容顯示在一個(gè)OutputTextBlock中,現(xiàn)在我們不使用task類,只使用我們的IAsyncOperation來(lái)做。
好,下面是C++同學(xué)的時(shí)間,請(qǐng)問(wèn),你能寫(xiě)出completed這個(gè)event的代碼么?并保證其運(yùn)行。那開(kāi)始吧。要知道FileOpenPicker::PickSingleFileAsync()返回的是一個(gè)Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^類型的操作:
Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ operation = openPicker->PickSingleFileAsync();//為了讓大家看清楚類型,就沒(méi)有用auto簡(jiǎn)寫(xiě),大家用auto的話會(huì)非常簡(jiǎn)單
對(duì)應(yīng)上面的四個(gè)接口,顯然,返回的是第二個(gè)接口IAsyncOperation<T TResult>^操作,那么它有一個(gè)Windows::Foundation::AsyncOperationCompletedHandler<TResult>^ 類型的Completed事件,那么我們的completed就應(yīng)該寫(xiě)成這樣:
operation->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>(//暫時(shí)省略);
好復(fù)雜!
還沒(méi)完,繼續(xù)。AsyncOperationCompletedHandler是一個(gè)Delegate,這個(gè)Delegate其實(shí)就是原來(lái)的函數(shù)指針?lè)庋b了一下,既然是函數(shù)指針,那么肯定有參數(shù),怎么尋找這個(gè)參數(shù)呢?把鼠標(biāo)移到這個(gè)方法上,按下F12就會(huì)談到Object Browse里面去,你就會(huì)發(fā)現(xiàn)這個(gè)Delegate,它有一個(gè)Invoke(。。。)方法,里面就是它的參數(shù)了。
另外,我們沒(méi)使用+=操作符,而是使用了=,為什么呢?因?yàn)镃ompleted是個(gè)屬性,不是個(gè)event。。。
回調(diào)函數(shù)的代碼段,我們用Lambda表達(dá)式來(lái)寫(xiě):
1 operation->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>([this](Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ asyncInfo, Windows::Foundation::AsyncStatus status) 2 {
3 //這里,貌似程序會(huì)在這里執(zhí)行3次,具體原理不太清楚。
4 if(status == Windows::Foundation::AsyncStatus::Completed)
5 {
6 //因?yàn)閳?zhí)行3次,所以我在這個(gè)里面加了一個(gè)計(jì)數(shù)器,但是最終的結(jié)果還是1,這個(gè)異步方法還是執(zhí)行了一次
7 //這里為什么是要Dispatcher->RunAsync呢,因?yàn)椋@是一個(gè)回調(diào)函數(shù),另一個(gè)線程中了。
8 //可以看到,這所有的一切都可以用then或者await來(lái)代替。
9 this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this](){
10 static int i = 0;
11 i++;
12 OutputTextBlock->Text = i.ToString();
13 }));
14 }
15 //如果執(zhí)行了operation->Canceled()方法會(huì)到這里
16 else if(status == Windows::Foundation::AsyncStatus::Canceled)
17 {
18 this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this](){
19 OutputTextBlock->Text = "Canceled";
20 }));
21 }
22 //操作出現(xiàn)錯(cuò)誤會(huì)到這里
23 else if(status == Windows::Foundation::AsyncStatus::Error)
24 {
25 this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this](){
26 OutputTextBlock->Text = "Error";
27 }));
28 }
29 //這里不能返回StorageFile^ 類型的對(duì)象,為神馬呢?因?yàn)門(mén)Result是void,如果你返回了,那么編譯器會(huì)提醒你很長(zhǎng)一段東西,你自己就會(huì)發(fā)現(xiàn)了
30 //return safe_cast<Windows::Storage::StorageFile^>(asyncInfo->GetResults());
31 });
具體的內(nèi)容都是上面的這段代碼了,有些東西我想再提醒一下。
1. 首先,我們來(lái)看第30行,因?yàn)槲矣X(jué)得這個(gè)方法是返回一個(gè)StorageFile對(duì)象的,所以我在Lambda方法中理應(yīng)返回它,但是如果返回的話,就是錯(cuò)誤的,為什么?原因是這里的返回值實(shí)際上是Invoke方法的返回值,在這里這個(gè)返回值是void的,所以你不能返回任何東西。
2. 使用asyncInfo->GetResults();可以得到你的結(jié)果,回頭看看那四個(gè)接口,有些返回TResult,有些返回void,是吧。
3. 在這個(gè)代碼段里,我們已經(jīng)跑到了另外一個(gè)線程中去了,如果你想操作UI,那么,你必須使用Dispatcher->RunAsync方法調(diào)度回UI線程,不信你可以試試。
4. 你可以在代碼中判斷現(xiàn)在IAsyncOperation的狀態(tài)。
哦,看看C#程序員的優(yōu)越性把:
op.Completed = (info, status) =>
{
if (status == AsyncStatus.Completed)
{
SyndicationFeed feed = info.GetResults();
UpdateAppWithFeed(feed);
}
else if (status == AsyncStatus.Canceled)
{
// Operation canceled
}
else if (status == AsyncStatus.Error)
{
// Error occurred, Report error
}
};
希望你還能堅(jiān)持。*^◎^*
看到這里你發(fā)現(xiàn)了么?這段代碼的功能其實(shí)是跟上一篇代碼的功能一模一樣,再把之前的代碼貼過(guò)來(lái)
1 create_task(openPicker->PickSingleFileAsync()).then([this](StorageFile^ file)
2 {
3 if (file)
4 {
5 OutputTextBlock->Text = "Picked photo: " + file->Name;
6 }
7 else
8 {
9 OutputTextBlock->Text = "Operation cancelled.";
10 }
11 }).then([this](task<void> t)
12 {
13 try{
14 t.get();
15 }catch(Platform::Exception^ e)
16 {
17 OutputTextBlock->Text = e->Message
18 }
19 });
額,希望你能明白,task為我們做了些什么東西。我來(lái)總結(jié)一下吧:
1. 沒(méi)有了復(fù)雜的completed回調(diào)函數(shù),操作完成之后,執(zhí)行then中的代碼,簡(jiǎn)單而明了。
2. then中的異步代碼是在UI線程中的,沒(méi)有Dispatcher->RunAsync方法,不是么?
3. 可以有多個(gè)then
4. 可以處理異常,不是更強(qiáng)大么?
task為我們做的,就是從30多行復(fù)雜的代碼精簡(jiǎn)到只有20行。
至于原理,大家可以閱讀參考文獻(xiàn)1,我暫時(shí)還沒(méi)有怎么理解。。。
posted on 2013-01-06 16:43
Dino-Tech 閱讀(1982)
評(píng)論(0) 編輯 收藏 引用