二重の義務を引き出す ContinueWith を使用してタスクを実行しています。タスクが正常に完了した場合は結果を処理し、エラーが発生した場合は例外を処理します。ただし、以下のコードは例外を適切に処理せず、未処理として登録し、プログラムをダウンさせます (投稿のために多少短縮されているため、完全ではない可能性があります)。
void _SqlServerDatabaseListLoader()
{
_ClearSqlHolders(true, false);
_SqlConnectionStringHolder.Database = "master";
if (_SqlConnectionStringHolder.IsComplete)
{
//Could time out put on its own thread with a continuation back on the UI thread for the popup
_TaskCanceller = new CancellationTokenSource();
_TaskLoader = Task.Factory.StartNew(() =>
{
IsLoadingSqlServerDatabaseList = true;
using (SqlConnection con = new SqlConnection(_SqlConnectionStringHolder))
{
// Open connection
con.Open(); //If this cause an error (say bad password) the whole thing bombs
//create a linq connection and get the list of database names
DataContext dc = new DataContext(con);
return new ObservableCollection<string>(dc.ExecuteQuery<string>("select [name] from sys.databases").ToObservableCollection());
}
}).ContinueWith(antecendant => _SqlServerDatabaseListLoaderComplete(antecendant.Result, antecendant.Exception),
_TaskCanceller.Token,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
}
void _SqlServerDatabaseListLoaderComplete(ObservableCollection<string> DatabaseList, AggregateException ae)
{
//Just show the first error
if (ae != null)
ToolkitDialog.ShowException(ae.InnerExceptions[0], ToolkitDialogType.Error, CustomDialogButtons.OK, "Error:", "Database List Error");
if(DatabaseList != null)
SqlServerDatabaseList = DatabaseList
//Set the running indicator
_TaskLoader = null;
_TaskCanceller = null;
IsLoadingSqlServerDatabaseList = false;
}
私はこれをやってのけるために TaskContinuationOptions.None を使用していますが、それは正しいと思います。これは、上記のクラスが継承する基本クラスで宣言されています。
protected Task _TaskLoader;
protected CancellationTokenSource _TaskCanceller;
エラーにならないシナリオで実行すると、すべてがうまくいき、データベース リストが表示されます。ただし、誰かがこの SQL Server ログイン資格情報に対して間違ったパスワードを指定したなどのエラーが発生した場合、エラーは処理されません。
しかし、Result パラメーターを渡すオプションを削除すると、すべてが正常に機能し、例外がキャッチされます。
void _SqlServerDatabaseListLoader()
{
_ClearSqlHolders(true, false);
_SqlConnectionStringHolder.Database = "master";
if (_SqlConnectionStringHolder.IsComplete)
{
//Could time out put on its own thread with a continuation back on the UI thread for the popup
_TaskCanceller = new CancellationTokenSource();
_TaskLoader = Task.Factory.StartNew(() =>
{
IsLoadingSqlServerDatabaseList = true;
using (SqlConnection con = new SqlConnection(_SqlConnectionStringHolder))
{
// Open connection
con.Open();
//create a linq connection and get the list of database names
DataContext dc = new DataContext(con);
//HAVE TO SET IN THE THEAD AND NOT RETURN A RESULT
SqlServerDatabaseList = new ObservableCollection<string>(dc.ExecuteQuery<string>("select [name] from sys.databases").ToObservableCollection());
}
}).ContinueWith(antecendant => _SqlServerDatabaseListLoaderComplete(antecendant.Exception),
_TaskCanceller.Token,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
}
void _SqlServerDatabaseListLoaderComplete(AggregateException ae)
{
//Just show the first error
if (ae != null)
ToolkitDialog.ShowException(ae.InnerExceptions[0], ToolkitDialogType.Error, CustomDialogButtons.OK, "Error:", "Database List Error");
//Set the running indicator
_TaskLoader = null;
_TaskCanceller = null;
IsLoadingSqlServerDatabaseList = false;
}
TPLがどのように機能するかを完全には理解していないと思います。複数の ContinueWith を作成しようとしましたが、違いはないようです。助けてくれてありがとう。