1. ホーム
  2. c#

[解決済み] 非同期メソッドにおけるrefとoutの引数

2023-03-28 06:50:26

質問

どなたか、なぜ async メソッドに refout の引数?少し調べてみたのですが、スタックのアンロールと関係があるとしかわかりませんでした。

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

非同期メソッドがrefとoutの引数を持つことができない理由を知っている人はいますか?

もちろんです。考えてみてください、非同期メソッドは通常 を返します。 をほぼ即座に返します。実際のロジックのほとんどが実行されるずっと前に...それは非同期で行われます。そのため out パラメータは最初の await 式の前に割り当てる必要があります。 ref の後に使われないようにするために、 パラメータに何らかの制限が必要かもしれません。 await 式の後に使われないようにするためです。

を持つ非同期メソッドを呼び出すことを考えます。 outref パラメータで、引数にローカル変数を使用します。

int x;
int y = 10;
FooAsync(out x, ref y);

その後 FooAsync が戻った後、メソッド自体が戻る可能性があります - したがって、それらのローカル変数はもはや論理的に存在しません... しかし、非同期メソッドはまだ効果的にその継続の中でそれらを使用することができます。大きな問題です。コンパイラはラムダ式と同じ方法で変数を捕捉する新しいクラスを作成することができますが、それは他の問題を引き起こします...他のことはさておき、あなたは ローカル 変数がメソッド中の任意の場所で変化してしまう可能性があります。控えめに言っても、奇妙です。

基本的に、これは outref のパラメータは async メソッドに渡すパラメータは、タイミングを考慮すると 代わりに、関心のあるすべてのデータを含む戻り値の型を使用してください。

にしか興味がないのであれば outref の前に変化するパラメータは、最初の await 式の前にパラメータが変化している場合は、常にメソッドを二つに分割することができます。

public Task<string> FooAsync(out int x, ref int y)
{
    // Assign a value to x here, maybe change y
    return FooAsyncImpl(x, y);
}

private async Task<string> FooAsyncImpl(int x, int y) // Not ref or out!
{
}

編集:実現可能でしょう。 out パラメータを Task<T> を使用して、戻り値のようにメソッド内で直接値を代入することができます。しかし、それは少し奇妙なことであり、それは ref パラメータには使えません。