使用await调用异步方法的正常行为是它的上下文保持不变,如下例所示:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
//main thread here
await SampleAsync();
//stays as main thread
var g = 10;
}
static async Task SampleAsync()
{
await Task.Delay(1000);
}
}
但是当我在Winforms主控制台方法调用中使用它时,这种行为不再成立:在调用await方法之后,线程从主线程更改为工作线程.为什么是这样?我希望它在等待调用后保持在Main(UI线程)上.
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainAsync().Wait();
}
static async Task MainAsync()
{
Application.Run(new Form1());
//Main Thread here
await Task.Delay(1000);
//Why does it turn in to worker thread here? ConfigureAwait(false) is not used here?!
var g = 5;
//Run other Application.Run() if certain conditions apply; but I need to be in the Main Thread.
}
如果你想知道我想要实现什么,我试图捕获异步方法中的错误,MainAsync,而不是Main,以便我可以避免从AggregateException(https://msdn.microsoft.com/en-us/magazine/JJ991977.aspx;图4)中解开错误.我还想留在UI线程中,这样我就可以在UI线程中运行其他Application.Run.
最佳答案 因为Application.Run是“运行”主线程上的延续,所以一旦Application.Run返回SynchronizationContext.Current,则为“UI线程”取消设置,因此await必须使用默认上下文,即ThreadPool.
因为此时没有UI,我建议在此时进行同步等待(.Wait())而不是await,这将确保您仍然在以后的Application.Run调用的同一个STA线程上.
编辑:没有看到你提到关于解开AggregateException,所有等待是用AggregateException做的相当于
catch(AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}
这导致重新引发AggregateException的第一个异常,而不会弄乱它的堆栈跟踪.