LoginSignup
4
2

More than 5 years have passed since last update.

structとTaskでハマった話

Posted at

問題

以下のコード、何が表示されると思いますか?

struct S
{
    public int Value;
    public S(int init) => Value = init;
    public async Task F()
    {
        Value++;
        await Task.CompletedTask;
    }
}

public static async Task Main()
{
    var s = new S(10);
    await s.F();
    Console.WriteLine(s.Value.ToString());
}

答えは 10 です。

では、以下のコード、何が表示されると思いますか?

struct S
{
    public int Value;
    public S(int init) => Value = init;
    public Task F()
    {
        Value++;
        return Task.CompletedTask;
    }
}

public static async Task Main()
{
    var s = new S(10);
    await s.F();
    Console.WriteLine(s.Value.ToString());
}

答えは 11 です。

どうしてこのようになるのでしょうか?

答えはこちら

解説

上記2つのコードの違いは S.F() がasyncメソッドかどうかという点です。

どうしてこうなるか、というと、asyncメソッドの場合Awaiterというものが作成されます。
これは、デリゲートの場合でいうファンクタオブジェクトのようなものです。
このAwaiterに構造体Sがコピーされてしまうため、S.F()が呼ばれるインスタンスはAwaiter.sであり、ローカル変数のsではないことが原因です。

解決策

  • Sをclassにする
  • F()の返り値をTask<S>にして、return thisしたうえで呼び出しをs = await s.F()にする

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2