C#にてActionを返す非同期メソッドをasyncメソッドでラップしたい
.Net Framework 4.6.1
以降のC#にて、戻り値がvoid
で引数にAction
を使う非同期処理用のメソッドに対してasync/awaitを適用する方法はあるのでしょうか?
下記のサンプルコードにおけるReadSQLWrapper
メソッドのように、Action
で戻ってきた値をラムダ式の外側で取得して、非同期実行の戻り値として返せることが理想です。
サンプルコード修正の前提条件としてDBManagerMock
自体は改修できないものとさせてください。
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
new Program().Execute();
}
private void Execute()
{
var sqls = new string[] { "select hoge;", "select fuga;", "select piyo;" };
//理想のコード
var tasks = sqls.Select(ReadSQLWrapper).ToArray();
Task.WaitAll(tasks); //Taskなら同期実行も非同期実行も思うがまま
tasks.Select(t => t.Result).ToList().ForEach(Console.WriteLine);
}
//懸案となる、うまく動作しないasyncの疑似メソッド
private async Task<string> ReadSQLWrapper(string sql)
{
var db = new DBManagerMock();
string result = "ダミーの初期化子"; //DBManagerMockのReadSQLメソッドのActionを返したい
//await db.ReadSQL(sql, r => { result = r; }); //エラー CS4008 'void' を待機することができません
return result;
}
}
//このクラスは改修不可
public class DBManagerMock
{
public void ReadSQL(string sql, Action<string> result)
{
//非同期でDB接続して結果を返す
result(string.Format("{0}の実行結果", sql));
}
}
}
AutoResetEvent
でも理想に近いコーディングは可能ですが、非同期実行時の実行待ち件数の上限があるため、async Task
を返す方がより利便性が高いと期待しています。
そもそもasync/awaitの理解に問題があるようでしたらご指摘いただければ幸いです。