投稿者 YuO  (社会人) 投稿日時 2016/9/28 13:05:46
> ContinueWithを使用した実装処理はどのように実装すればよいのでしょうか。
まじめに書くとAsync/Awaitを使うのに比べて非常に面倒になります。
なので,Async/Awaitだけで書いた方がよいと思います。

まず,単純にメソッドを一度まとめてしまうと,
Private Async Function UpdateTableAsync(ByVal tableName As StringByVal dt As DataTable) As Task
    Try
        '対象のテーブルを一括削除。  
        Using con As New SqlConnection(strConnection)
            Using cmd As New SqlCommand()
                Await con.OpenAsync()
                cmd.Connection = con
                cmd.CommandText = "DELETE FROM " & tableName
                cmd.CommandTimeout = 3600
                Await cmd.ExecuteNonQueryAsync()
                con.Close()
            End Using
        End Using

        '対象のテーブルにBulkCopy。  
        Using con As New SqlConnection(strConnection)
            Using sqlBulkCopy As New SqlBulkCopy(con)
                sqlBulkCopy.DestinationTableName = tableName
                sqlBulkCopy.BulkCopyTimeout = 3600
                Await con.OpenAsync()
                Await sqlBulkCopy.WriteToServerAsync(dt)
                con.Close()
            End Using
        End Using
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Function
のようになります。
DELETEに失敗した時点でBulk Copyする意味が無いため,Try-Catchの範囲を変更していますが。

なお,Async/Awaitを使っている場合,UIスレッドから呼び出されたとすると,
・Awaitしているメソッドが内部でTaskを作っているような場合は非UIスレッド
・それ以外の部分はUIスレッドで動作します。
# ConfigureAwait(False)をしている場合を除く。この場合はメソッド終了まで非UIスレッドで動きます。

メソッドに分割し直すと,
'対象のテーブルを一括削除。  
Private Async Function DeleteTableAsync(ByVal tableName As StringAs Task
    Using con As New SqlConnection(strConnection)
        Using cmd As New SqlCommand()
            Await con.OpenAsync().ConfigureAwait(False)
            cmd.Connection = con
            cmd.CommandText = "DELETE FROM " & tableName
            cmd.CommandTimeout = 3600
            Await cmd.ExecuteNonQueryAsync().ConfigureAwait(False)
            con.Close()
        End Using
    End Using
End Function

'対象のテーブルにBulkCopy。  
Private Async Function BulkCopyToTableAsync(ByVal tableName As StringByVal dt As DataTable) As Task
    Using con As New SqlConnection(strConnection)
        Using sqlBulkCopy As New SqlBulkCopy(con)
            sqlBulkCopy.DestinationTableName = tableName
            sqlBulkCopy.BulkCopyTimeout = 3600
            Await con.OpenAsync().ConfigureAwait(False)
            Await sqlBulkCopy.WriteToServerAsync(dt).ConfigureAwait(False)
            con.Close()
        End Using
    End Using
End Function

Private Async Function UpdateTableAsync(ByVal tableName As StringByVal dt As DataTable) As Task
    Try
        Await DeleteTableAsync(tableName)
        Await BulkCopyToTableAsync(tableName, dt)
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Function
でしょうか。
UIに関係ない部分をメソッドに切り出して,ConfigureAwait(False)によってUIスレッドに戻す処理を行わないようにしています。


ちなみに,これらをContinueWith使って書き直すのは結構骨が折れます。
Private Function UpdateTableAsync(ByVal tableName As StringByVal dt As DataTable) As Task
    Dim task1 = DeleteTableAsync(tableName)
    Dim task2 = task1.ContinueWith(Function (t) BulkCopyToTableAsync(tableName, dt) End Function, TaskContinuationOptions.OnlyOnRanToCompletion).UnWrap()
    Dim task3 = task1.ContinueWith(Sub (t) MessageBox.Show(t.Exception.Message) End Sub, CancellationToken.None,TaskContinuationOptions.OnlyOnOnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext())
    Dim task4 = task2.ContinueWith(Sub (t) MessageBox.Show(t.Exception.Message) End Sub, CancellationToken.None,TaskContinuationOptions.OnlyOnOnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext())

    Return Task.WhenAll(task3, task4)
End Function
たぶん,こんな感じです (コンパイルすらしていません)。
なお,Async/Awaitは状態機械を作るので,上記とは異なるコードを作成します。