简体   繁体   English

如何等待await / async方法完成

[英]How to wait until await / async methods finish

I have the following Async method: 我有以下Async方法:

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();
    }
}

I don't want to execute SetupInvoiceGrid until _invoiceTypes, _invoiceAccounts and _ds have finished. 在_invoiceTypes,_invoiceAccounts和_ds完成之前,我不想执行SetupInvoiceGrid。

Any clue? 任何线索? Am I doing it right? 我做得对吗? Should I be using Task instead of await? 我应该使用Task而不是等待吗?


I have come up with this code that seems is working and looks fine to me but don't really know if its correct: 我已经想出了这个代码似乎正在工作,看起来很好,但我不知道它是否正确:

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();
}

I answered the original(?) question on how to handle the finish of ProcessSearchAsync itself here . 我回答关于如何处理的结束原来的(?)问题ProcessSearchAsync本身在这里

To run tasks in parallel (as asked in the comments), here's your code modified, it gets a little complicated because of invoiceTypes == null and _invoiceAccounts == null checks. 要并行运行任务(如评论中所述),这里修改了代码,因为invoiceTypes == null_invoiceAccounts == null检查,它会变得有点复杂。 Note the way the checks are implemented below slightly changes the logic (previously it did WCF calls only if both _invoiceTypes and _invoiceAccounts were null - what if only one of them is null?): 注意下面实现检查的方式稍微改变了逻辑(以前只有当_invoiceTypes和_invoiceAccounts都为null时,它才会进行WCF调用 - 如果只有其中一个为空,会怎样?):

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();
}

Minor changes to what you've got there will do what you want. 你所拥有的东西的微小变化将做你想要的。 You can start new tasks and then do other stuff and then await just before you go on. 你可以开始新的任务,然后做其他的事情,然后在你继续之前等待。 As @Noseratio has helpfully pointed out, this snippet below isn't production-ready because I'm not checking for error conditions (like null references, etc). 正如@Noseratio已经有用地指出的那样,下面的这个片段不是生产就绪的,因为我没有检查错误条件(如null引用等)。 The point is that you can succinctly and elegantly do these things in parallel without having to resort to using very much of the Tasks API. 关键是你可以简洁而优雅地并行完成这些工作,而不必使用大量的Tasks API。 One adjustment I made worth pointing out is that you want to move the calls to Dispose into the continuation (ie, after all your await s) because if you try to Dispose right after calling the *Async methods you stand a good chance of killing off your WCF clients halfway through getting a response and the awaits will probably wind up throwing exceptions (which I'm not catching). 我提出的一个值得指出的调整是你想要将Dispose的调用移到延续中(即,在你所有的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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM