読者です 読者をやめる 読者になる 読者になる

空談録

http://artfulplace.net/blogs/ からひっこしつつ

asyncなメソッドをasyncなしのメソッドで待機する

✝闇✝

というわけで確実にクソパターンですがasync Taskのメソッドをasyncではないメソッドで待機、取得してみます
全部async awaitに対応するほうが安泰です

状況

なんでこんなことしてるんっていうとExpression Treeとかが挟まったりそもそもasync awaitなメソッドが呼ばれる保証が全くないからです
async awaitを使う前提がないので全部async awaitな関数に書き換えるくらいなら無茶してしまったほうが楽だと思い
(怖い人が見たら私刺されそう)

ところでReflectionで普通の関数awaitしたらどうなるんでしょう
たぶん落ちそうだな…

コード

というわけでクソコードです、ご確認ください

private async void taskAwait<T>(Func<Task<T>> ts, Action<T> x)
{
    var r = await ts();
    x(r);
}

private T taskWait<T>(Func<Task<T>> fr)
{
    var f = false;
    T trs = default(T);
    Task.Factory.StartNew(() => taskAwait2(fr, x => { trs = x; f = true; }));
    System.Threading.SpinWait.SpinUntil(() => f, 40000);
    return trs;
}

イエーイメッチャクソコード


使い方はこんな感じ

private void foo()
{
    var res = taskWait(async () => await hoge());
    //...
}

// private async Task<int> hoge() { }

アクセス修飾子は適当に直してください

asyncな関数をawait以外で待機するとデッドロックするか落ちるのでawait以外では受けれません
なのでasync awaitなデリゲートを作成します
そしてデリゲートの実行自体はasync voidの中で行い、他では触らないようにします

awaitしたメソッドが終わるか40秒経過すると抜けます
awaitしたメソッドをキャンセルする仕組みが特にないのは問題な気もしつつも、そもそもTaskじゃないのにキャンセルってあるんですかね…
なんかあった気もしますが


ちなみにデスクトップ向けだと普通にasyncを使わないパターンが選択できるのでそっち使いましょう

このコードどこからどういう用途で呼ぶかにもよりますがTaskから呼んで非同期スレッド内で完結する領域なら問題ないかと
まあ使わないのが一番いいんですけどね!

この辺で