让我们暂时搁置一下,question是否应该在Silverlight应用程序的上下文中尝试类似同步操作。如果我使用ManualResetEvent,如下面的代码所示:
static string result;
static AutoResetEvent are = new AutoResetEvent(false);
static ManualResetEvent mre = new ManualResetEvent(false);
public static string AsyncCall()
{
string url = "https://stackoverflow.com/feeds/tag/silverlight";
WebClient w = new WebClient();
w.DownloadStringCompleted += new DownloadStringCompletedEventHandler(w_DownloadStringCompleted);
w.DownloadStringAsync(new Uri(url), url);
mre.WaitOne();
return result;
}
static void w_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
result = e.Result;
mre.Set();
}
正如您期望阅读ManualResetEvent on MSDN,“当控制线程完成活动时,它调用Set方法来表示等待线程可以继续。”,当在w_DownloadStringCompleted中调用Set()时, control返回到在AsyncCall中开始等待的等待线程。这是使用.NET 4.0运行时发生的情况。 AsyncCall中的线程被阻止,直到下载完成并调用Set。
如果我在Silverlight 4中运行相同的代码,将调用DownloadStringAsync,但控件永远不会到达w_DownloadStringCompleted回调。一旦调用了WaitOne(),AsyncCall中的那个线程就会挂起,并且处理DownloadStringAsync的线程永远不会到达回调。我看到线程到达SL4中的下载回调的唯一方法是来自AsyncCall的线程是否从AsyncCall返回。所以Set()永远不会被调用。
为什么ManualResetEvent在Silverlight 4中没有按预期工作?为什么它与.NET 4不同? 这可能是微软对异步设计模式的执行吗? 或者有什么我想念的东西?
由于
答案 0 :(得分:3)
Silverlight中的网络回调将始终以与发起时相同的线程到达。例如,如果在UI线程上创建WebClient.DownloadStringAsync(即,在按钮单击事件上),则回调调用将排队以在同一UI线程上传递。但是,您对mre.WaitOne()
的调用阻止了UI线程,因此永远不会调用回调,并且mre.Set()
调用永远不会发生。
所以是的,这是网络调用的异步性中的一种强制执行 - 你真的不能进行同步调用,即使它们似乎是同步的。