【问题标题】:How to properly catch asynchronous task?如何正确捕获异步任务?
【发布时间】:2017-01-13 21:51:57
【问题描述】:

我想知道为什么这个Click 事件中的异常没有被捕获?除了statusLabel 向用户显示进程的状态之外,代码中没有任何花哨的东西。 myDataTable 是一个局部变量;目标是将结果分配给它。

GetDataTable 也必须是异步的吗?

public DataTable GetDataTable(string connectionString, string cmdText)
{
    DataTable dt = new DataTable();
    using (SqlConnection conn = new SqlConnection(connectionString)) {
        using (SqlCommand comm = new SqlCommand(cmdText, conn)) {
            conn.Open();
            dt.Load(comm.ExecuteReader);
            return dt;
        }
    }
}

private async void Button1_Click(object sender, EventArgs e)
{
    try {
        statusLabel.Text = "Processing...";

        Task<DataTable> dtTask = Task.Run(() => GetDataTable(connectionString, commandText));
        await dtTask;
        myDataTable = dtTask.Result;

        statusLabel.Text = "Done!";
    } catch (Exception ex) {
        MessageBox.Show("Error");
    }
}

更新

我设法通过使GetDataTable() 返回DataTableTask 并将.Open.ExecuteReader 更改为它们的异步对应项来解决这个问题。对于另一种方法,Try 块内的那三行我减少为一行:

myDataTable = await GetDataTable(connectionString, commandText);

感谢大家的耐心等待!

【问题讨论】:

  • 您正在使用 Result 属性 .. 还不如不使用 Task ..
  • 我假设问题是在非异步方法上使用 await。我可以准确地分析发生了什么(因此是评论而不是答案)。您可以完全删除该行或使用 GetAwaiter().GetResult() 代替该行和下一行。见stackoverflow.com/questions/16877262/…stackoverflow.com/questions/17284517/…
  • 或者正如 G-Man 所说,如果您正在同步等待结果,甚至不要使用任务。
  • @G-Man,不过,在分配myDataTable = dtTask.Result 之前,他正在等待dtTask。所以它仍然是异步的。与myDataTable = await dtTask基本相同。
  • @AwonDanag 我无法在我的测试代码中重现您的问题。您确定GetDataTable() 是在抛出异常还是您没有吞下它?如果出于测试目的,您将 GetDataTable() 的内容替换为仅抛出异常会怎样?

标签: c# async-await try-catch


【解决方案1】:

不要使用Task.Run 将同步方法转换为异步方法,而是使用ExecuteReaderAsync真正异步加载数据。之后,你的代码就变得简单多了:

public async Task<DataTable> GetDataTable(string connectionString, string cmdText)
{
    DataTable dt = new DataTable();
    using (SqlConnection conn = new SqlConnection(connectionString)) {
        using (SqlCommand comm = new SqlCommand(cmdText, conn)) {
            conn.Open();
            var reader=await comm.ExecuteReaderAsync();
            dt.Load(reader);
            return dt;
        }
    }
}

private async void Button1_Click(object sender, EventArgs e)
{
    try {
        statusLabel.Text = "Processing...";

        myDataTable = await GetDataTable(connectionString, commandText);

        statusLabel.Text = "Done!";
    } catch (Exception ex) {
        MessageBox.Show("Error");
    }
}

GetDataTable 变成了一个异步方法,它异步执行查询并返回一个读取器:

var reader=await comm.ExecuteReaderAsync();
dt.Load(reader);
return dt;

之后,设置myDataTable 变量只需要使用await

myDataTable = await GetDataTable(connectionString, commandText);

【讨论】:

  • 酷!正如我在编辑中所说,我使用了 Open()ExecuteReader() 的异步对应项,而且效果似乎很好......我看到你只使用了 ExecuteReaderAsync() - 会有区别吗?
【解决方案2】:

相信您正在寻找的答案就在这里:Async void exception handling

我假设 'Button1_Click' 方法应该是 'async void'?:

private async void Button1_Click(object sender, EventArgs e)
{
    ...
}

【讨论】:

  • 是的,我错过了那个。它是异步的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-03
相关资源
最近更新 更多