即使在异常之后也可以执行任务

时间:2018-04-05 15:59:33

标签: c# task task-parallel-library

下面的任务中的方法 RelatoriosEstaticos.AbrirDataAtual 返回已经在方法本身处理的异常,问题是任务继续执行下一行 var links = ListArquivos.ListaLinksDownlaod(驱动程序); 取决于要执行的方法 AbrirDataAtual(),它也会抛出异常。我试图在方法中处理,将任务放在Try / catch中,但没有任何效果,方法 ListaLinksDownlaod 中始终存在异常,甚至不应该到达那里。

如何停止执行任务,例如当我们发送CancellationToken时,但这次是在发生异常时。

private async Task<List<IWebElement>> Acessar(IWebDriver driver, string data, CancellationToken ct)
{
    return await Task.Run(() =>
    {
        ct.ThrowIfCancellationRequested();

        LoginNgin.Login(config.User, config.Password, driver);

        RelatoriosEstaticos.AbrirRelatoriosEstaticos(driver);

        RelatoriosEstaticos.AbrirDataAtual(driver, data);

        var links = ListArquivos.ListaLinksDownlaod(driver);

        MethodInvoker action = delegate { pgbStatus.Maximum = links.Count(); };
        pgbStatus.BeginInvoke(action);

        return links;
    });
}

1 个答案:

答案 0 :(得分:1)

如果没有看到AbrirDataAtual的实际实现,就无法确定,但看起来这个方法肯定是处理不应该在那里处理的异常。

通常,方法应该处理异常 如果它能正确处理 (通过正确我的意思是它可以将应用程序恢复到其中的状态程序可以安全地继续,告知用户有关错误等),否则它根本不应该处理它并让异常传播给方法的调用者。

根据您的问题说明,AbrirDataAtual没有(且无法)正确处理异常,因此您不应该在那里捕获异常(或如果必须在那里抓住,你应该re-throw。以下所有方法(包括ListArquivos.ListaLinksDownlaod)将被跳过,处理异常。问题解决了!

以下示例显示如何直接在任务中处理异常(在AbrirDataAtual中删除异常处理之后)。但它很可能仍然不是这种异常处理程序的最佳位置,但同样,找到这样的地方需要完整的源代码,所以以此为例澄清我在说什么约:

private async Task<List<IWebElement>> Acessar(IWebDriver driver, string data, CancellationToken ct)
{
    return await Task.Run(() =>
    {
        ct.ThrowIfCancellationRequested();

        LoginNgin.Login(config.User, config.Password, driver);

        RelatoriosEstaticos.AbrirRelatoriosEstaticos(driver);

        try
        {
            RelatoriosEstaticos.AbrirDataAtual(driver, data);

            var links = ListArquivos.ListaLinksDownlaod(driver);

            MethodInvoker action = delegate { pgbStatus.Maximum = links.Count(); };
            pgbStatus.BeginInvoke(action);

            return links;
        }
        catch (Exception)//Use more specific exception type if possible
        {
            //Do all neccesary to properly handle the exception
        }
    });
}

如果你仍然相信AbrirDataAtual方法是处理异常的正确位置,另一种方法是修改AbrirDataAtual以返回布尔标志,指示它的操作成功/失败,例如:

bool AbrirDataAtual(IWebDriver driver, string data)
{
    try
    {
        //Do all the neccessary stuff
        ...

        //Indicate that AbrirDataAtual succeeded
        return true;
    }
    catch(Exception)
    {
        //Handle exception properly
        ...

        //Indicate that AbrirDataAtual failed
        return false;
    }
}

private async Task<List<IWebElement>> Acessar(IWebDriver driver, string data, CancellationToken ct)
{
    return await Task.Run(() =>
    {
        ct.ThrowIfCancellationRequested();

        LoginNgin.Login(config.User, config.Password, driver);

        RelatoriosEstaticos.AbrirRelatoriosEstaticos(driver);

        if (RelatoriosEstaticos.AbrirDataAtual(driver, data))
        {
            //Continue execution
            var links = ListArquivos.ListaLinksDownlaod(driver);

            MethodInvoker action = delegate { pgbStatus.Maximum = links.Count(); };
            pgbStatus.BeginInvoke(action);

            return links;
        }
        else
        {
            //AbrirDataAtual failed
            return null;
            //or throw exception if appropriate
            throw new Exception();
        }
    });
}