短い答え:いいえ。.NET は、変数を見つけるためにスコープ チェーンをたどる必要はありません。
長い答え:
次の例から始めます。
static Func<string> CaptureArgs(int a, int b)
{
return () => String.Format("a = {0}, b = {1}", a, b);
}
static void Main(string[] args)
{
Func<string> f = CaptureArgs(5, 10);
Console.WriteLine("f(): {0}", f());
// prints f(): a = 5, b = 10
}
CaptureArgs
メソッド内で、スタック上a
にb
存在します。直感的に、無名関数で変数を参照すると、関数が返され、スタック フレームがポップされてメモリから削除a
さb
れます。(これは、上向きの funargs 問題と呼ばれます)。
C# は、上向きの funargs の問題に悩まされることはありません。これは、舞台裏では、無名関数は、コンパイラによって生成されたクラスに対する手の込んだ構文糖衣にすぎないためです。上記の C# コードは次のようになります。
private sealed class <>c__DisplayClass1
{
// Fields
public int a;
public int b;
// Methods
public string <CaptureArgs>b__0()
{
return string.Format("a = {0}, b = {1}", this.a, this.b);
}
}
コンパイラは の新しいインスタンスを作成して返し、 メソッドに渡されたおよびフィールドを<>c__DisplayClass1
初期化し(これにより、およびがスタックからヒープ上に存在するフィールドに効果的にコピーされます)、それを呼び出し元に返します。Callingは実際には への呼び出しです。a
b
a
b
CaptureArgs
a
b
f()
<>c__DisplayClass1.<CaptureArgs>b__0()
a
および でb
参照されるはバニラ フィールドであるため<CaptureArgs>b__0
、デリゲートによって直接参照でき、特別な種類のスコープ チェーン ルールは必要ありません。