2010-08-16 64 views
8

我將一些代碼從完整的.NET框架移植到WP7版本,並且遇到了同步和異步調用的問題。在Silverlight WP7中僞造同步調用

string response; 
string requestString = GenerateReqString(); 
HttpWebRequest req = (HttpWebRequest) WebRequest.Create("endpoint"); 
req.Method = "POST"; 
req.ContentType = "text/xml"; 

req.ContentLength = requestString.Length; 

StreamWriter sw = new StreamWriter (req.GetRequestStream(), System.Text.Encoding.ASCII); 
sw.Write(requestString); 
sw.Close(); 

StreamReader sr = new StreamReader(req.GetResponse().GetResponseStream()); 
response = sr.ReadToEnd(); 
sr.Close(); 

然後將響應字符串解析爲方法返回的對象列表。

我遇到的問題是沒有辦法在Silverlight/WP7中同步進行調用。如果我使用回調函數,我將得到不同函數的響應,並且不能從原始函數返回它。有沒有辦法讓這個調用同步或者從CallBack函數返回到啓動異步調用的方法?

回答

11

您需要以不同的方式思考問題。要使異步事物「感覺」同步,最簡單的方法就是重構代碼以使用'continuation passing style'。

實質上,不是調用返回值然後處理該值的函數,而是調用一個函數,並將匿名函數作爲委託傳遞給它。被調用的函數將調用委託,傳入字符串。

下面是一個例子,它使用匿名函數和lambda表達式:

void DoSomethingAsync(Action<string> callback) { 
    HttpWebRequest req; // TODO: build your request 

    req.BeginGetResponse(result => { 
     // This anonymous function is a closure and has access 
     // to the containing (or enclosing) function. 
     var response = req.EndGetResponse(result); 

     // Get the result string and call the callback 
     string resultString = null; // TODO: read from the stream 

     callback(resultString); 
    }, null); 
} 

這是一個一半的溶液。接下來的部分是實際調用這個。想象一下,你有一個ICommand實例或更簡單的按鈕點擊事件,需要調用該函數和「獲取字符串」。您不必「獲取字符串」,而是調用此函數並提供回調方法(這將是一個閉包)。

void btnGo_Click(object sender, EventArgs e) { 
    DoSomethingAsync(resultString => { 
     // This anonymous function is called when the web request has 
     // finished and has your string. 

     // Now that we have the string, we can go and process it. 
     ProcessWebResponseResult(resultString); 
    }); 
} 

這裏確實是一個很好的文章,解釋的概念進一步: http://blogs.msdn.com/b/wesdyer/archive/2007/12/22/continuation-passing-style.aspx

+0

可以說ProcessWebResponseResult()從字符串中創建一個對象,並調用DoSomethingAsync()需要返回該對象的函數。那可能嗎? – CACuzcatlan 2010-08-17 17:05:49

+0

這是錯過了重點。調用DoSomethingAsync的方法將函數傳遞給DoSomethingAsync。傳遞的函數是「如何處理這個函數的結果」。隨着您的需要更多,您可以爲呼叫鏈添加額外的繼續功能。 – 2010-08-17 17:38:01

+0

這是你如何看待一個正常運行的程序:'A(); B(); C();'。然而,當你使用'延續傳球風格'執行時,你告訴每個功能完成後該怎麼做。而不是「我從這個函數中得到我的結果」,而是通過委託人說「我告訴這個函數如何處理它的結果」。 – 2010-08-17 17:41:42

2

首先,我建議嘗試獲得舒適與異步但如果你真的想/需要異步調用同步,您可以使用ManualResetEvent達到預期的結果轉換。

這裏,如果使用一個簡單的例子:

public ManualResetEvent _event = new ManualResetEvent(false); 

... 
{ 
    ... 
    var wc = new WebClient(); 
    wc.OpenReadCompleted += new OpenReadCompletedEventHandler(ReadCompleted); 
    wc.OpenReadAsync(uri); 

    // block until async call is complete 
    _event.WaitOne(); 
} 

private static void ReadCompleted(object sender, OpenReadCompletedEventArgs e) 
{ 
    ... 
    // set event to unblock caller 
    _event.Set(); 
} 

現在,你的代碼將上線_event.WaitOne();阻塞,直到_event.Set();被調用。

祝你好運!

-2

最好是異步執行此操作,以便用戶可以繼續與設備交互。

我懷疑你想這樣做的原因是爲了防止用戶與某些控件進行交互,直到你的請求完成。

接受此方法的方法是隱藏或禁用在請求處理期間不應與之交互的UI元素。

+0

將所有這些內容抽象出來並開始在更高層次上開始異步執行,在此時,您會希望同步執行低級別請求,因爲您已經在某種工作線程上。 – 2011-02-13 03:02:12