2012-09-26 33 views
5

我有一个方法返回一个数据表。我认为使用.net 4.0我可以只是异步逻辑并返回数据。但是这段代码返回的是空的Datatable对象。任何想法这个代码有什么问题。使用异步.net 4.0返回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]; 
} 
+0

您不能在.NET 4.0或C#4中使用'async' /'await'。这是C#5中的一项新功能,取决于.NET 4.5中的类型。 –

+4

乔恩 - 因为他使用TaskEx.Run,​​我猜他正在使用异步定位包,它可以让你定位4.0并使用异步/等待 –

回答

9

首先,你不能使用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); 
} 

如果你要开始一个任务并立即等待就可以了,你可能也只是调用该方法同步。

+0

好吧,那么如何在.net 3.5中做到这一点,如果可以帮助那个乔恩? ? – Malcolm

+0

我只打算使用4.0作为异步,所以我现在不会使用它。 – Malcolm

+0

@Malcolm:任何你不想使用4.5的理由? –

2

如果要使用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); 
} 
8

我自己的源代码。

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

不错,但是您还应该将取消令牌传递给OpenAsync和ExecuteReaderAsync方法,以便取消也会阻止这些方法 –

+0

谢谢您实际提供的解决方案。你在哪里获得取消标记传入? – toddmo

+0

您可以使用'using'模式关闭处理中的所有内容。 – toddmo