使用异步 .net 4.0 返回数据表



>我有一个返回数据表的方法。我认为使用 .net 4.0 我可以异步逻辑并返回数据。但是此代码返回空数据表对象。任何想法这个代码有什么问题。

public DataTable GetData(string sql, string connectionName)
{
    DataTable dt = (DataTable)GetDataAsync(sql, connectionName).AsyncState;
    return dt;
}
private async Task<DataTable> GetDataAsync(string sql, string connectionName)
{
    return await TaskEx.Run(() => { return FillData(sql, connectionName); });
}
private DataTable FillData(string sql, string connectionName)
{
    SqlConnection conn = _connections.Where(w => w.ConnectionName == connectionName).Single().Connection;
    SqlDataAdapter adp = new SqlDataAdapter(sql, conn);
    DataSet ds = new DataSet();
    adp.Fill(ds);
    return ds.Tables[0];
}

首先,不能将 async/await 与 .NET 4 或 C# 4 一起使用。这是 C# 5 中的一项新功能。有一些CTP安装在.NET 4之上,但这些CTP中存在明显的错误 - 不要使用它们。应使用 .NET 4.5 的完整发布版本,其中包括 C# 5 编译器。(所有这些都在Visual Studio 2012中。

其次,正如Cuong Le所展示的那样,你使用了任务的错误属性。Result属性是你如何得到Task<T>的结果。

第三,在更改使用 Result 属性后,您将阻止要获取的表 - 使其毫无意义。这:

public DataTable GetData(string sql, string connectionName)
{
    DataTable dt = (DataTable)GetDataAsync(sql, connectionName).Result;
    return dt;
}

。在很大程度上等效于:

public DataTable GetData(string sql, string connectionName)
{
    return FillData(sql, connectionName);
}

如果要启动任务并立即等待它,则不妨同步调用该方法。

我自己的源代码。

public static async Task<DataTable> GetDataTableAsync(this System.Data.Common.DbCommand command, CancellationToken cancellationToken, string tableName = null)
    {
        TaskCompletionSource<DataTable> source = new TaskCompletionSource<DataTable>();
        var resultTable = new DataTable(tableName ?? command.CommandText);
        DbDataReader dataReader = null;
        if (cancellationToken.IsCancellationRequested == true)
        {
            source.SetCanceled();
            await source.Task;
        }
        try
        {
            await command.Connection.OpenAsync();
            dataReader = await command.ExecuteReaderAsync(CommandBehavior.Default);
            resultTable.Load(dataReader);
            source.SetResult(resultTable);
        }
        catch (Exception ex)
        {
            source.SetException(ex);
        }
        finally
        {
            if (dataReader != null)
                dataReader.Close();
            command.Connection.Close();
        }
        return resultTable;
    }
如果你想

使用async代码,那么不要阻止它。此外,请确保您使用的是异步定位包,而不是异步 CTP。

private async Task<DataTable> GetDataAsync(string sql, string connectionName)
{
  return await TaskEx.Run(() => { return FillData(sql, connectionName); });
}
private async GetAndProcessDataAsync()
{
  DataTable table = await GetDataAsync("my sql", "my connection name");
  ProcessData(table);
}

最新更新