【问题标题】:Return DataTable using async .net 4.0使用异步 .net 4.0 返回 DataTable
【发布时间】:2012-09-26 05:34:51
【问题描述】:

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

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];
}

【问题讨论】:

  • 您不能在 .NET 4.0 或 C# 4 中使用 async / await。这是 C# 5 中的一项新功能,取决于 .NET 4.5 中的类型。
  • Jon - 因为他使用的是 TaskEx.Run,​​我猜他使用的是异步定位包,它可以让您定位 4.0 并使用 async/await

标签: .net c#-4.0 async-await


【解决方案1】:

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

其次,正如 Cuong Le 所示,您使用了错误的任务属性。 Result 属性是您获得Task&lt;T&gt; 的结果的方式。

第三,在更改为使用 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);
}

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

【讨论】:

  • 好的,如果可以帮助 Jon,我该如何在 .net 3.5 中执行此操作??
  • 我只打算使用 4.0 进行异步,所以我现在不会使用它。
  • @Malcolm:有什么理由不想使用 4.5?
  • 我以为你说它只是 5.0。是的,我可以使用 4.5。
  • @Malcolm:我说它是在 C# 5.0 中,这就是你在 .NET 4.5 中使用的。
【解决方案2】:

我自己的源代码。

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

【讨论】:

  • 很好,但是您还应该将取消令牌传递给 OpenAsync 和 ExecuteReaderAsync 方法,以便取消也会停止这些
  • 感谢您实际提供解决方案。您从哪里获得取消令牌以传递?
  • 您可以使用using 模式为您关闭所有内容。
  • 这里只有reader的创建是异步执行的。同时,数据加载是同步完成的:resultTable.Load(dataReader); 这是一个耗时的操作。
【解决方案3】:

如果你想使用async 代码,那么don't block on it。另外,请确保您使用的是 Async Targeting Pack 而不是 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2012-04-28
    • 2016-10-14
    相关资源
    最近更新 更多