2010-08-16 65 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