更新:まあ、今私は行ってそれをしました:私はそれが正しい振る舞いであると真剣に疑っているので、これについてマイクロソフトにバグレポートを提出しました。とはいえ、この質問に関して何を信じるべきかはまだ100%わかりません。ですから、「正しい」ものはある程度の解釈に開かれていることがわかります。
私の考えでは、Microsoftはこれがバグであることを受け入れるか、using
ステートメント内の可変値型変数の変更が未定義の動作を構成すると応答します。
また、その価値については、少なくともここで何が起こっているのかについては推測できます。コンパイラがクロージャのクラスを生成し、ローカル変数をそのクラスのインスタンスフィールドに「リフト」しているのではないかと思います。using
ブロック内にあるので、フィールドを作成していますreadonly
。LukeHが他の質問へのコメントで指摘したように、これにより、フィールド自体の変更などのメソッド呼び出しが防止さMoveNext
れます(代わりにコピーに影響します)。
注:読みやすさのためにこの質問を短くしましたが、まだ正確に短いわけではありません。元の(長い)質問全体については、編集履歴を参照してください。
ECMA-334の関連セクションであると私が信じていることを読み通しましたが、この質問に対する決定的な答えを見つけることができないようです。私は最初に質問を述べ、次に興味のある人のためにいくつかの追加のコメントへのリンクを提供します。
質問
を実装する可変値型がある場合は、IDisposable
(1)using
ステートメント内のローカル変数の値の状態を変更するメソッドを呼び出すことができ、コードは期待どおりに動作します。ただし、ステートメント内のクロージャ内using
で問題の変数をキャプチャすると、(2)値への変更はローカルスコープに表示されなくなります。
この動作は、変数がクロージャー内およびusing
ステートメント内でキャプチャされた場合にのみ明らかになります。using
1つ( )または他の条件(閉鎖)のみが存在する場合は明らかではありません。
ステートメント内のクロージャー内で可変値型の変数をキャプチャすると、using
そのローカル動作が変わるのはなぜですか?
以下は、項目1と2を示すコード例です。どちらの例も、次のデモンストレーションMutable
値タイプを利用します。
struct Mutable : IDisposable
{
int _value;
public int Increment()
{
return _value++;
}
public void Dispose() { }
}
1.using
ブロック内の値型変数の変更
using (var x = new Mutable())
{
Console.WriteLine(x.Increment());
Console.WriteLine(x.Increment());
}
出力コードは以下を出力します:
0 1
using
2.ブロック内のクロージャ内の値型変数をキャプチャする
using (var x = new Mutable())
{
// x is captured inside a closure.
Func<int> closure = () => x.Increment();
// Now the Increment method does not appear to affect the value
// of local variable x.
Console.WriteLine(x.Increment());
Console.WriteLine(x.Increment());
}
上記のコードは次のように出力します。
0 0
さらなるコメント
Monoコンパイラは、私が期待する動作を提供することに注意してください(ローカル変数の値への変更は、using
+クロージャの場合でも表示されます)。この振る舞いが正しいかどうかは私にはわかりません。
この問題に関する私の考えの詳細については、こちらを参照してください。