2012-09-26 78 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