かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

awaitでLazyみたいなことをしたい

以前にid:neueccさんが、Build Insider Offlineで披露してたAsyncLazyがかっこよかったので元ネタからソースを拝借。

public class AsyncLazy<T> : Lazy<Task<T>>
{
    public AsyncLazy(Func<T> valueFactory) :
        base(() => Task.Factory.StartNew(valueFactory)) { }

    public AsyncLazy(Func<Task<T>> taskFactory) :
        base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap()) { }

    public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}

Lazy<T>のTの部分をTask<T>にしてGetAwaiterを定義してやるだけでawaitで値をとってこれるLazyができちゃうなんて柔軟すぎる…。気になるのはid:neueccさんが、ちょっと手を入れて使ってますといったところ。何かこれで不都合がでたのかなぁ。

あとスライドにしれっとAsyncLazy.WhenAll(p.Name, p2.Name, p3.Name)みたいなものが出てたけどAsyncLazyがTaskを包んだだけのLazyだとしたら以下のような実装でAsyncLazyの実装はいけそう?

public static class AsyncLazy
{
    public static Task WhenAll<T>(params AsyncLazy<T>[] ls)
    {
        // Lazy<Task<T>>[]からTask<T>[]に変換してTask.WhenAllする
        return Task.WhenAll(ls.Select(l => l.Value).ToArray());
    }
}

ふむふむ。