我认为您在这里有些困惑。您所要求的已经可以使用来实现System.Threading.Tasks
,在C#5中,async
和await
只是为同一功能提供更好的语法糖。
让我们使用一个Winforms示例-在表单上放置一个按钮和一个文本框,然后使用以下代码:
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext());
}
private int DelayedAdd(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
运行它,你会看到(一)它不会阻塞UI线程以及(b)你没有得到通常的“跨线程操作无效”错误-除非你删除TaskScheduler
从最后一个参数ContinueWith
,在那样的话
这是沼泽标准的连续通过样式。魔术发生在TaskScheduler
类中,特别是在检索的实例中FromCurrentSynchronizationContext
。将其传递给任何延续,您将告诉延续必须在称为FromCurrentSynchronizationContext
方法的任何线程(在本例中为UI线程)上运行。
从某种意义上来说,等待者稍微更加复杂,因为他们知道他们从哪个线程开始,并且需要在哪个线程上进行延续。所以上面的代码可以写成一点点更自然:
private async void button1_Click(object sender, EventArgs e)
{
int a = await DelayedAddAsync(5, 10);
int b = await DelayedAddAsync(a, 20);
int c = await DelayedAddAsync(b, 30);
int d = await DelayedAddAsync(c, 50);
textBox1.Text = d.ToString();
}
private async Task<int> DelayedAddAsync(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
这两个应该看起来非常相似,事实上,他们是非常相似的。该DelayedAddAsync
方法现在返回a Task<int>
而不是一个int
,因此a await
只是将延续拍打到其中的每一个上。主要区别在于它沿着每一行的同步上下文传递,因此您不必像上一个示例中那样显式地进行同步。
从理论上讲,差异要大得多。在第二个示例中,方法中的每一行button1_Click
实际上都是在UI线程中执行的,但是任务本身(DelayedAddAsync
)在后台运行。在第一个示例中,除了我们明确附加到UI线程的同步上下文的分配之外,所有内容都在后台运行。textBox1.Text
真正有趣的是await
-等待者能够跳入和跳出相同方法而没有任何阻塞调用。你打电话await
,当前线程再次进入处理消息,并且当它这样做时,awaiter将正好拿起它离开的地方,在它英寸离开同一线程,但在你的条件Invoke
/ BeginInvoke
的问题,我”对比很抱歉,您应该早就停止这样做了。
await
功能方面,这似乎极不可能。继续传递只是很多语法上的糖。可能对WinForms进行了其他一些不相关的改进,应该有所帮助吗?但是,那将属于.NET框架本身,而不是C#。