2012-09-26 5 views
5

データテーブルを返すメソッドがあります。私は.net 4.0を使っていると思った。ロジックを非同期にしてデータを返すことができた。しかし、このコードはnull Datatableオブジェクトを返します。どのようなアイデアがこのコードで間違っている。async .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

Jon - 彼はTaskEx.Runを使用しているので、彼は非同期ターゲティングパックを使用していると推測しています。これは4.0をターゲットにしてasync/awaitを使用します。 –

答えて

9

まず、あなたはそれは.NET 4の上にインストールのCTPがあったのC#5の新機能ですが、明確なバグがある.NET 4またはC#4でasync/awaitを使用することはできませんそれらのCTPでは - を使用しないでください。 C#5コンパイラを含む.NET 4.5のフルリリース版を使用する必要があります。 (これはVisual Studio 2012にあります)

第2に、Cuong Leが示したように、タスクの間違った特性を使用しています。 Resultプロパティは、Task<T>の結果をどのように取得するかです。

第3に、Resultプロパティを使用するように変更した後、テーブルがフェッチされるのをブロックして、無意味にします。この:

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

タスクを起動し、すぐにそれを待つつもりなら、あなたにもちょうど同期メソッドを呼び出すことができます:

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

は...とほぼ同等です。

+0

これでJonを助けることができます。 ? – Malcolm

+0

私は非同期用に4.0を使用する予定だったので、今は使用しません。 – Malcolm

+0

@Malcolm:あなたは4.5を使いたくない理由は何ですか? –

2

asyncコードを使用する場合は、don't block on itです。また、非同期CTPではなくAsync Targeting Packを使用していることを確認してください。

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

'使用する'パターンを使って、あなたのためにすべてを閉じることができます。 – toddmo

関連する問題