私は、作業中のプログラム用に一種の単純なプラグイン フレームワークを開発しました。その一部として、プラグインの派生元となる抽象基本クラスがあります。例えば:
public abstract class Plugin
{
public Task StartAsync()
{
Task.Run(Start);
}
protected abstract void Start();
}
問題は、StartAsync を待機して、プラグインで (可能な範囲で) すべてを完了できるようにしたいということです。これにより、すべてを try-catch でラップし、プラグインがアプリをダウンさせないようにすることができます (おそらくアプリ ドメインを使用する必要があることを認識しており、必要に応じて使用します)。
async Start メソッドを使用してプラグインを定義するまで、これはすべて正常に機能していました。
public class MyPlugin
{
protected override async void Start()
{
// await some awaitable stuff
}
}
もちろん、私の抽象基本クラスは Start を待っていません (コンパイル時に非同期になることを認識していないため)。そのため、MyPlugin が例外をスローした場合、フレームワークはそれをキャッチする機会がありません。明らかにこれは、プラグインの実装者が予期せぬ非同期処理を行った場合にも当てはまりますが、メソッド シグネチャに async を追加するだけで、非常に簡単に自分自身を撃つ方法のように思えます。「await if awaitable」オペレーターを求めるのは不合理だと思いますが、この問題から抜け出す方法について誰かが考えているかどうか疑問に思いました(または、まったく問題ではなく、私は不合理です)。
これが私の頭の中で見ようとしているものです:
public abstract class Plugin
{
public Task StartAsync()
{
Task.Run(() => awaitif Start());
}
protected abstract void Start();
}
最後に、プラグインの大部分は単純で同期的である可能性が高いため、Start を非同期にしたり、Task を返したりすることは避けたいと思います。