4

我有以下异步方法:

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。

有什么线索吗?我做对了吗?我应该使用任务而不是等待吗?


我想出了这段代码,它似乎可以正常工作并且对我来说看起来不错,但真的不知道它是否正确:

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

2 回答 2

3

我在这里回答了关于如何处理ProcessSearchAsync自身完成的原始(?)问题。

invoiceTypes == null要并行运行任务(如评论中所要求的),这是您修改的代码,由于和_invoiceAccounts == null检查,它变得有点复杂。请注意下面实现检查的方式稍微改变了逻辑(以前它只在 _invoiceTypes 和 _invoiceAccounts 都为空时才调用 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();
}
于 2013-08-17T17:21:28.740 回答
0

对你所拥有的东西进行微小的改变就会做你想做的事。您可以开始新任务,然后做其他事情,然后在继续之前等待。正如@Noseratio 有帮助地指出的那样,下面的这个片段不是生产就绪的,因为我没有检查错误条件(如null引用等)。关键是您可以简洁而优雅地并行执行这些操作,而无需大量使用 Tasks API。我做出的一个值得指出的调整是,您希望将调用移至Disposecontinuation(即,在您的所有awaits 之后),因为如果您在调用 *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();
}
于 2013-08-17T17:44:41.320 回答