かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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());
    }
}

ふむふむ。