读史蒂芬·克雷伊(Stephen Cleary)对not blocking on Async code的看法,我这样写
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...);
textBox1.Text=json;
}
到目前为止,我了解到ConfigureAwait
之后,该方法将在GetStringAsync
返回之后继续在其他上下文上运行。
但是如果我想使用像MessageBox
这样的东西(UI)怎么办
public static async Task<JObject> GetJsonAsync(Uri uri)
{
if(someValue<MAXVALUE)
{
using (var client = new HttpClient())
{
//var jsonString = await client.GetStringAsync(uri); //starts the REST request
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
else
{
MessageBox.Show("The parameter someValue is too big!");
}
}
我可以这样做吗?
更复杂的呢?
public static async Task<JObject> GetJsonAsync(Uri uri)
{
if(someValue<MAXVALUE)
{
try{
using (var client = new HttpClient())
{
//var jsonString = await client.GetStringAsync(uri); //starts the REST request
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
catch(Exception ex)
{
MessageBox.Show("An Exception was raised!");
}
}
else
{
MessageBox.Show("The parameter someValue is too big!");
}
}
我可以这样做吗?
现在,我想也许所有消息框都应该在GetJsonAync外部调用,这是一个很好的设计,但是我的问题是可以完成上述操作吗?
答案 0 :(得分:2)
我可以这样做吗? [使用MessageBox]
是的,但是主要是因为它与异步/等待或线程无关。
MessageBox.Show()
很特殊,它是一个静态方法,并记录为线程安全的。
您可以随时从任何线程显示MessageBox。
所以也许这是一个错误的示例,但是标题中确实有MessageBox。
public static async Task<JObject> GetJsonAsync(Uri uri)
{
try{
... // old context
... await client.GetStringAsync(uri).ConfigureAwait(false);
... // new context
}
catch
{
// this might bomb
someLabel.Text = "An Exception was raised!";
}
}
在此示例中,可能存在代码路径,其中catch在旧的环境中运行,而其他路径则在新的上下文中运行。
最重要的是:您不知道,应该承担最坏的情况。
答案 1 :(得分:1)
我不会使用消息框,因为它非常有限且已过时。 另外,弹出窗口很烦人。 使用您自己的用户控件,该控件可按照您希望的方式进行用户交互。
在Winforms / WPF /(我猜是UWP)的上下文中,只有一个线程可以操纵UI。其他线程可以通过一系列最终被调用的动作向其发出工作。
这种体系结构可防止其他线程不断地在UI上戳戳,这可能会使UX非常不稳定(并且线程不安全)。
(在Winforms中)与UI工作队列进行通信的唯一方法是通过System.Windows.Form.Controls.BeginInvoke实例方法,该方法在每个窗体和控件上都可以找到。
在您的情况下:
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...).ConfigureAwait(false);
BeginInvoke(UpdateTextBox, json);
}
private void UpdateTextBox(string value)
{
textBox1.Text=json;
}