web-dev-qa-db-ja.com

C#5.0で非同期の子オーバーライドを強制する方法

私は、複数のクライアントオブジェクトがインターフェースを介して特定の機能を実装することが期待されているシステムで作業しており、その機能を継続して非同期に実行したい(実装がI/Oバウンドであり、すべてのクライアントオブジェクトがこの機能をできるだけ早く完了するようにしてください)。 C#「5.0」でSP1のVisual Studio非同期CTP更新を使用しています。

抽象クラスの子オブジェクトで非同期動作を強制するための推奨プラクティスは何ですか(以下を参照)?仮想メソッドのアプローチを使用して「非同期」メソッドの使用を(明らかに)強制することはできません。 'Task'戻り型のみが必要です。これは、子オブジェクトで非同期動作をまったく要求しないことを意味しますか?その場合、戻り値の型は単に「void」である必要がありますか?

パブリックインターフェイスは、現在のシステム設計の残念な結果ですが、それは別の問題です。明らかに、 'BaseFoo'をバイパスして 'IFoo'インターフェイスを実装するだけの非同期ユーザーを強制することはできませんでした。

コードは次のとおりです。

public interface IFoo
{
    void Bar(); //NOTE: Cannot use 'async' on methods without bodies.
}

public abstract class BaseFoo : IFoo
{
    public async void Bar()
    {
        await OnBar(); //QUESTION: What is the right "async delegation" pattern?
    }

    protected virtual async Task OnBar()
    {
        await TaskEx.Yield();
    }
}

public class RealFoo : BaseFoo //NOTE: May be implemented by 3rd party
{
    protected override async Task OnBar()
    {
        //CLIENT: Do work, potentially awaiting async calls

        await TaskEx.Yield(); //SECONDARY QUESTION: Is there a way to avoid this if there are no 'awaits' in the client's work?
    }
}
44
Lars Kemmann

メソッドがasync/awaitを使用して実装されるかどうかは、実装詳細です。メソッドの方法動作は契約の詳細であり、通常の方法で指定する必要があります。

メソッドにTaskまたはTask<T>、それは非同期であることを意図しており、おそらく実装が難しいでしょうなし非同期です。

一方、await式がnever不完全な実装(テスト目的など)がある場合、なぜ誰かにaを持たない非同期メソッドを強制的に記述させたいのでしょうawaitはとにかく呼び出しますか?あなたはexpecting IOにバインドされる実装ですが、実装がハードコードされたデータなどを使用したい特別なケースがあるかもしれません。

基本的に、メソッドのドキュメントでこれを処理する必要があります-実装者がそれを読むことを信頼できない場合は、とにかくチャンスがありません:(

83
Jon Skeet

Jonの答えに加えて、 タスクベースの非同期パターン を使用している場合、メソッド名の末尾にAsyncを付ける必要があります。

インターフェイスを実装している場合

public interface IFoo
{
    Task BarAsync();
}

asyncキーワードを使用してこれを実装する必要があることは明らかです。

16
dav_i