如何等待等待/async方法完成
本文关键字:等待 async 方法 何等待 | 更新日期: 2023-09-27 18:27:59
我有以下异步方法:
private async void ProcessSearch()
{
// get catalogs on first search
if (_invoiceTypes == null && _invoiceAccounts == null)
{
var confWcf = new Data.ConfigurationWCF();
_invoiceTypes = await confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
_invoiceAccounts = await confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
confWcf.Dispose();
}
var seekWcf = new DataSeekWCF();
_ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
seekWcf.Dispose();
if (_ds != null)
{
SetupInvoiceGrid();
}
}
在_invoiceTypes、_invoiceAccounts和_ds完成之前,我不想执行SetupInvoiceGrid。
有线索吗?我做得对吗?我应该使用Task而不是等待吗?
我已经想出了这个代码,它似乎正在工作,对我来说看起来很好,但不知道它是否正确:
private void btnSearch_Click(object sender, EventArgs e)
{
lock (lockObj)
{
if (_isBusy)
return;
else
_isBusy = true;
}
ShowPleaseWait(Translate("Searching data. Please wait..."));
if (_invoiceTypes == null && _invoiceAccounts == null)
{
var t = GetCatalogs();
t.ContinueWith(t2 =>
{
if (t.IsCompleted) ProcessSearch();
});
}
else
{
ProcessSearch();
}
}
private async Task GetCatalogs()
{
// get catalogs on first search
Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF();
var task1 = confWcf.GetInvoiceTypesAsync(1);
var task2 = confWcf.GetInvoiceAccountsAsync(1);
confWcf.Dispose();
await Task.WhenAll(task1, task2);
_invoiceTypes = task1.Result;
_invoiceAccounts = task2.Result;
if (_invoiceTypes != null)
{
cboInvoiceType.DataSource = _invoiceTypes.Tables["invoice_types"];
cboInvoiceType.DisplayMember = "description";
cboInvoiceType.ValueMember = "code";
}
}
private async void ProcessSearch()
{
var seekWcf = new Data.SeekWCF();
_ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
seekWcf.Dispose();
if (_ds != null)
{
SetupInvoiceGrid();
}
HidePleaseWait();
}
我在这里回答了关于如何处理ProcessSearchAsync
本身的完成的原始(?)问题。
要并行运行任务(如注释中所述),以下是您修改的代码,由于invoiceTypes == null
和_invoiceAccounts == null
检查,它变得有点复杂。请注意,下面的检查实现方式稍微改变了逻辑(以前它只在_invoiceTypes和_invoiceAccounts都为null的情况下进行WCF调用——如果其中只有一个为null怎么办?):
private async Task ProcessSearchAsync()
{
Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF();
Task</*typeof _invoiceTypes*/> t1;
Task</*typeof _invoiceAccounts*/> t2;
if (_invoiceTypes == null)
t1 = confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
else
{
var tsc1 = new TaskCompletionSource</*typeof _invoiceTypes*/>();
t1 = tsc1.Task;
tsc1.SetResult(_invoiceTypes);
}
if ( _invoiceAccounts == null )
t2 = confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
else
{
var tsc2 = new TaskCompletionSource</*typeof _invoiceAccounts*/>();
t2 = tsc2.Task;
tsc2.SetResult(_invoiceAccounts);
}
DataSeekWCF seekWcf = new DataSeekWCF();
Task</*typeof _ds*/> t3 = seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
await Task.WhenAll(new Task[] {t1, t2, t3});
_invoiceTypes = t1.Result;
_invoiceAccounts = t2.Result;
ds = t3.Result;
if (_ds != null)
{
SetupInvoiceGrid();
}
confWcf.Dispose();
seekWcf.Dispose();
}
对现有内容的微小更改将满足您的需求。你可以开始新任务,然后做其他事情,然后在继续之前等待。正如@Noseratio所指出的,下面的这个片段还没有准备好生产,因为我没有检查错误条件(如null
引用等)。重点是,您可以简洁而优雅地并行完成这些工作,而不必使用大量的Tasks API。我做的一个值得指出的调整是,您希望将对Dispose
的调用转移到continuation中(即,在所有await
之后),因为如果您在调用*Async方法之后立即尝试Dispose
,则很有可能在获得响应的中途杀死WCF客户端,并且awaits
可能最终会抛出异常(我没有发现)。
private async void ProcessSearchAsync()
{
Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF();
Task</*typeof _invoiceTypes*/> t1;
Task</*typeof _invoiceAccounts*/> t2;
// get catalogs on first search
if (_invoiceTypes == null && _invoiceAccounts == null)
{
t1 = confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
t2 = confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
}
DataSeekWCF seekWcf = new DataSeekWCF();
Task</*typeof _ds*/> t3 = seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
_invoiceTypes = await t1;
_invoiceAccounts = await t2;
_ds = await t3;
if (_ds != null)
{
SetupInvoiceGrid();
}
confWcf.Dispose();
seekWcf.Dispose();
}