1. ホーム
  2. c#

[解決済み] なぜRoslynでは非同期ステートマシンはクラス(構造体)ではないのですか?

2023-05-15 02:45:36

質問

この非常に単純な非同期メソッドについて考えてみましょう。

static async Task myMethodAsync() 
{
    await Task.Delay(500);
}

これをVS2013(Roslynコンパイラ以前)でコンパイルすると、生成されるステートマシンはstructになります。

private struct <myMethodAsync>d__0 : IAsyncStateMachine
{  
    ...
    void IAsyncStateMachine.MoveNext()
    {
        ...
    }
}

VS2015(Roslyn)でコンパイルすると、生成されたコードはこのようになります。

private sealed class <myMethodAsync>d__1 : IAsyncStateMachine
{
    ...
    void IAsyncStateMachine.MoveNext()
    {
        ...
    }
}

ご覧の通り、Roslynは(構造体ではなく)クラスを生成します。私の記憶が正しければ、古いコンパイラ (CTP2012 だと思います) の非同期/待機サポートの最初の実装もクラスを生成していましたが、パフォーマンス上の理由から構造体に変更されたようです。(場合によっては、箱詰めやヒープ割り当てを完全に回避できることもあります...) (参照 この )

なぜこれがRoslynで再び変更されたのか、ご存知の方はいらっしゃいますか?(私はこれに関して何の問題もありませんし、この変更が透過的でどのコードの動作も変えないことも知っています。)

編集します。

Damien_The_Unbeliever の回答 (およびソースコード :) がすべてを説明していると思います。Roslyn の記述された動作は、デバッグビルドにのみ適用されます (そして、これはコメントにある CLR の制限のために必要なのです)。Releaseでは、構造体も生成されます(その利点はすべてありますが・・・)。これは、EditとContinueの両方をサポートし、実稼働時のパフォーマンスを向上させる、非常に賢いソリューションのように思えます。興味深い内容でした。参加してくれたみなさん、ありがとうございました。

どのように解決するのですか?

私は予知していませんでしたが、最近のRoslynはオープンソースなので、コードを漁って説明することができます。

そして、ここでも の 60 行目、AsyncRewriter の を見つけることができます。

// The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class.
var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct;

このように struct を使うことにも魅力がありますが、大きな利点は 編集と続行 の中で動作させることができるようになりました。 async メソッドで動作するようにすることが、より良い選択肢として選ばれたのは明らかです。