現在、いくつかの非同期メソッドを使用してアプリケーションを作成しようとしています。すべての IO はインターフェイスの明示的な実装を通じて実行されており、操作を非同期にする方法について少し混乱しています。
私の見解では、実装には 2 つのオプションがあります。
interface IIO
{
void DoOperation();
}
オプション1:暗黙的な実装を async で実行し、暗黙的な実装内で結果を待機します。
class IOImplementation : IIO
{
async void DoOperation()
{
await Task.Factory.StartNew(() =>
{
//WRITING A FILE OR SOME SUCH THINGAMAGIG
});
}
#region IIO Members
void IIO.DoOperation()
{
DoOperation();
}
#endregion
}
オプション2:明示的な実装を非同期に実行し、暗黙的な実装からのタスクを待機します。
class IOAsyncImplementation : IIO
{
private Task DoOperationAsync()
{
return new Task(() =>
{
//DO ALL THE HEAVY LIFTING!!!
});
}
#region IIOAsync Members
async void IIO.DoOperation()
{
await DoOperationAsync();
}
#endregion
}
これらの実装のいずれかが他の実装よりも優れているのでしょうか、それとも私が考えていない別の方法があるのでしょうか?
ベストアンサー1
どちらのオプションも正しくありません。同期インターフェイスを非同期に実装しようとしています。そうしないでください。問題は、DoOperation()
が戻ったときに操作がまだ完了していないことです。さらに悪いことに、操作中に例外が発生した場合 (IO 操作では非常に一般的です)、ユーザーはその例外を処理する機会がありません。
あなたがすべきことはインターフェースを変更する非同期になるようにします。
interface IIO
{
Task DoOperationAsync(); // note: no async here
}
class IOImplementation : IIO
{
public async Task DoOperationAsync()
{
// perform the operation here
}
}
こうすることで、ユーザーは操作が であることを認識しasync
、それを実行できるようになりますawait
。これにより、コードのユーザーは に切り替えることをほぼ強制されますasync
が、これは避けられません。
StartNew()
また、実装で を使用するのは単なる例だと思います。非同期 IO を実装するためにそれは必要ありません。 (さらに悪いことに、がnew Task()
ないため、動作しません。)Start()
Task