web-dev-qa-db-ja.com

インターフェースと非同期メソッド

アプリケーションがあります。このアプリケーションは、インターフェイスを使用してデータベースにアクセスします。このインターフェイスは、多くのクラスで実装できます。たとえば、EF 4.4を使用しますが、他のクラスはより効率的なEF5を使用できます。将来的には非同期メソッドを使用するため、EF6を使用する可能性があります。この例では、すべてのメソッドがEFを使用していますが、おそらく他のオプションは他の方法を使用できます。

インターフェースを使用してアプリケーションを1回コーディングし、構成ファイルに従って1つの実装または他の実装を使用するため、1つの場所(コンストラクター)でコードを変更するだけで、クラスのインスタンス化に新しいオプションを追加できます。それはインターフェイスに割り当てられます。

現時点では、クラスのすべてのメソッドはasyncではありませんが、将来EF6を使用する場合は非同期メソッドを使用したいので、使用するクラスが可能かどうかわかりませんEF6およびインターフェイスの実装では、asyncメソッドを使用できます。

EF6の非同期メソッドの場合、async/awiatパターンを使用するため、クラスのメソッドではasync属性を使用する必要があります。これにより、EF6の非同期メソッドを呼び出すときにawaitキーワードを使用できます。

しかし、このクラスは、初めて同期メソッド用のインターフェースを実装できますか?

メインアプリケーションでコードを変更することなく多くの実装を使用できる方法はありますか?非同期メソッドを使用する実装もあれば、同期メソッドを使用する実装もあります。

49
Álvaro García

asyncは署名の一部ではないため、インターフェイスを実装するメソッドがasyncであるかどうかを実際に考慮する必要はありません。プロパティのタイプ、戻り値のタイプ、メソッドの名前、アクセシビリティ。

realの違いは、asyncメソッドがTaskまたはTask<T>を返す必要があることです。一方、非同期ではないメソッドは現在返されている可能性が高いです。 voidまたは何らかのタイプ、T直接。

アプリケーションを「将来の証拠」にしたい場合、すべてのインターフェイスがTaskまたはTask<T>を返し、EF4/EF5実装の場合は結果を完成したタスクにラップすることを保証することが1つのオプションですただし、それらは同期的に実行されます。

Task.FromResultは.NET 4.5で追加されましたが、お持ちでない場合は、簡単に独自のコードを作成できます。

public static Task<T> FromResult<T>(T result)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(result);
    return tcs.Task;
}

既に完了したタスクを単に返すCompletedTaskメソッドを書くこともできます:(効率上の理由から単一のタスクをキャッシュします。)

private static Task _completedTask;
public static Task CompletedTask()
{
    return _completedTask ?? initCompletedTask();
}

private static Task initCompletedTask()
{
    var tcs = new TaskCompletionSource<object>();
    tcs.SetResult(null);
    _completedTask = tcs.Task;
    return _completedTask;
}

これらの2つのメソッドは、すべてのメソッドが何らかのタイプのTaskを返すプロセスを単純化しますが、これを行うと、C#5.0を使用してawait結果。

58
Servy