実際の.NET実装とその背後にある決定が不思議です。匿名メソッドで取得された値が.NETで実装される方法
たとえば、Javaでは、匿名クラスで使用されるすべての取得値は最終的なものでなければなりません。この要件は.NETで削除されたようです。
また、参照型とは対照的に、値型の取得値の実装に違いがありますか?それが実装されていますどのように見つけるの
おかげ
実際の.NET実装とその背後にある決定が不思議です。匿名メソッドで取得された値が.NETで実装される方法
たとえば、Javaでは、匿名クラスで使用されるすべての取得値は最終的なものでなければなりません。この要件は.NETで削除されたようです。
また、参照型とは対照的に、値型の取得値の実装に違いがありますか?それが実装されていますどのように見つけるの
おかげ
最も簡単な方法は、それを試してみることです。キャプチャされた変数を使用するコードを作成し、コンパイルしてからReflectorを参照してください。 変数がキャプチャされ、の値はではありません。これは、この分野のJavaとC#の大きな違いの1つです。
少なくとも1つのキャプチャされた変数を含むスコープの各レベルは、キャプチャされた変数のフィールドを持つ新しいクラスになります。複数のレベルがある場合、内部スコープには、次のスコープのフィールドなどがあります。スタック上の本物のローカル変数は、自動生成されたクラスのインスタンスへの参照になります。
ここでは例です:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Action> actions = new List<Action>();
for (int i=0; i < 5; i++)
{
int copyOfI = i;
for (int j=0; j < 5; j++)
{
int copyOfJ = j;
actions.Add(delegate
{
Console.WriteLine("{0} {1}", copyOfI, copyOfJ);
});
}
}
foreach (Action action in actions)
{
action();
}
}
}
(あなたはもちろんのコピーを取らない場合は、異なる結果を得る - 実験!)これは、このようなコードにコンパイルされています
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Action> actions = new List<Action>();
for (int i=0; i < 5; i++)
{
OuterScope outer = new OuterScope();
outer.copyOfI = i;
for (int j=0; j < 5; j++)
{
InnerScope inner = new InnerScope();
inner.outer = outer;
inner.copyOfJ = j;
actions.Add(inner.Action);
}
}
foreach (Action action in actions)
{
action();
}
}
class OuterScope
{
public int copyOfI;
}
class InnerScope
{
public int copyOfJ;
public OuterScope outer;
public void Action()
{
Console.WriteLine("{0} {1}", outer.copyOfI, copyOfJ);
}
}
}
キャプチャされた変数に対するすべてのの参照は、生成されたクラスのインスタンスを経由するので、単なるコピーではありません。 (この例では、コード内の他のものはキャプチャされた変数を使用していませんが、簡単に想像することができます)外部ループの任意の反復に対して、5つの新しいインスタンスはすべて1つのインスタンスOuterScope
を共有します。デリゲートで余分なコードを試してみると、デリゲートがどのように影響するのかを確認できます。copyofI
変更は次のデリゲートで見られます。次の代理人が別のインスタンスInnerScope
を使用するため、copyOfJ
の変更は表示されません。
こんにちは、非常に良い説明。コンパイラがローカル変数へのコピーをせずに何を生成するかを示すこともできます。 –