C#は非同期関数呼び出し同期関数または同期関数呼び出し関数を呼び出します
-
12-12-2019 - |
質問
一般的なSQLデータベース操作を実行するためのC#.NET 4.5ライブラリを書いています(バックアップ、復元、実行スクリプトなど)。このライブラリはコンソールアプリとGUIアプリの両方で使用されるため、各操作の同期機能と非同期関数の両方を持ちたいが、どこでもコードを重複したくない。それで私がそれを見るように、私は2つの選択肢を持っています:
-
同期関数内の作業を行うコードを書き込み、次のように非同期関数のタスクに折り返すだけです。
public void BackupDB(string server, string db) { // Do all of the work and long running operation here } public async Task BackupDBAsync(string server, string db) { await Task.Factory.StartNew(() => BackupDB(server, db)).ConfigureAwait(false); }
-
非同期関数内の作業を行うコードを書き込み、.wait()を使用して同期関数から呼び出します。
public async Task BackupDBAsync(string server, string db) { // Do all of the work and long running operation here, asynchronously. } public void BackupDB(string server, string db) { BackupDBAsync(server, db).Wait(); // Execution will wait here until async function finishes completely. }
もう一方のオプションはどれより良いですか?一つのベストプラクティスですか?それとも他の(より良い)代替案はありますか?
.wait()を使用する警告は、ASYNC関数のすべてのAWAITステートメントが、デッドロックを避けるために.configureAwait(false)を使用しなければならないことがわかります(ここで説明されているように、UIにアクセスする必要がないライブラリを書いているのでまたはWebContext私はそれをするのは安全です。
SQLライブラリに使用できる同期機能と非同期関数の両方を使用するように注意しますので、同期関数で作業を行う場合は、同期関数を呼び出し、ASYNCで作業を行う場合関数、私は彼らの非同期関数を呼びます。
- 編集:この質問を投稿しました"REL=" NOFOLLOW NOREFERRER "> MSDNフォーラムの上にありますここでオフィシャルMSの応答を試してみる -
解決
このライブラリはコンソールアプリとGUIアプリの両方で使用されるため、各操作の同期機能と非同期関数の両方を持ちたいが、いたるところでコードを重複したくない。
最高の答えは以下のとおりです。
Stephen Toubには、このトピックに関する2つの優れたブログ投稿があります。
他のヒント
私は一部のアプリケーションが同期的にロードされるデータを必要とし、他の他のアプリケーションを必要としていると同様の状況を持っていました。私は私のDataLoaderを呼び出したインターフェースを作成することにしました:
public interface IIMViewModelDL {
void LoadProjects(AssignProjects callback);
}
.
absecrojectsコールバックは、プロジェクトの返されたリストを取り込む単純なデリゲートです。
public delegate void AssignProjects(IEnumerable<Project> results);
.
今の美しさは、あなたが同期または非同期で取られているかどうかを知らずにあなたがインターフェースを使って働くことができるということです。
3つのクラスが作成されます.1つのベース、1つの同期、および1つの非同期:
public abstract class BaseViewModelDL {
protected IEnumerable<Project> LoadProjects() {
BaseServiceClient client = new BaseServiceClient();
return client.Projects();
}
public class SynchronousViewModelDL : BaseViewModelDL, IIMViewModelDL {
public void LoadProjects(AssignProjects callback) {
callback(base.LoadProjects());
}
public class AsyncIMViewModelDL : BaseViewModelDL, IIMViewModelDL {
public void LoadProjects(AssignProjects callback) {
BackgroundWorker loadProjectsAsync = new BackgroundWorker();
loadProjectsAsync.DoWork += new DoWorkEventHandler(LoadProjectsAsync_DoWork);
loadProjectsAsync.RunWorkerCompleted += new RunWorkerCompletedEventHandler(LoadProjectsAsync_RunWorkerCompleted);
loadProjectsAsync.RunWorkerAsync(callback);
}
void LoadProjectsAsync_DoWork(object sender, DoWorkEventArgs e) {
var results = new ObservableCollection<Project>(base.LoadProjects());
e.Result = new object[] { results, e.Argument };
}
void LoadProjectsAsync_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
AssignProjects callback = (AssignProjects)((object[])e.Result)[1];
IEnumerable<Project> results = (IEnumerable<Project>)((object[])e.Result)[0];
callback(results);
}
.
今、あなたのアプリケーションでは、データをロードする方法を決めることができます...これはIOCコンテナを介して注入される可能性がありますが、デモ目的のためにハードコードされています:
private ViewModelDataLoaders.IIMViewModelDL dataLoader = new ViewModelDataLoaders.AsyncIMViewModelDL();
.
今、あなたの呼び出しコードは同じように見え、それが非同期か同期かどうかの賢明なものではありません:
private void LoadProjects() {
dataLoader.LoadProjects(
delegate(IEnumerable<Project> results) {
Projects = new ObservableCollection<Project>(results);
});
}
.
Unit Testing(Sync)、WPFアプリケーション(非同期)、およびコンソールアプリケーション(SYNC)の定期的にこれを使用します。
は、待ち時間を使用せずに、吸音時にメソッドをマークするという点ではないようです。 Asyncとしてマークを付けても、それを非同期にしないように、AWAITSを使用することができます(AWAITで実行されたコードは非同期的に起こるもので、残りのASYNCメソッドは非同期的には非同期的に実行されます):< / P>
通常、asyncキーワードによって変更されたメソッドには、少なくとも1つの待機式またはステートメントが含まれています。この方法は、最初の待機式に到達するまで同期的に実行され、その時点で待望のタスクが完了するまで中断されます。その間、制御はメソッドの呼び出し元に返されます。メソッドにAWAIT式またはステートメントが含まれていない場合は、同期的に実行されます。コンパイラ警告は、その状況がエラーを示す可能性があるため、待機していないAsyncメソッドに警告します。詳細については、コンパイラ警告CS4014を参照してください。
から: async < / P>