C#의 참조 대신 사본을 캡처하도록 Lambda 기능을 알려주는 방법?
문제
나는 C#을 배우고 있었고 Lambdas를 이해하려고 노력하고 있습니다. 아래 샘플에서 10 번 10 번 인쇄합니다.
class Program
{
delegate void Action();
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 10; ++i )
actions.Add(()=>Console.WriteLine(i));
foreach (Action a in actions)
a();
}
}
분명히, 람다 뒤에 생성 된 클래스는 int i
변수이며 루프가 반복 될 때마다 동일한 참조에 새 값을 할당합니다. C ++ 0x 구문과 같이 Lamda가 대신 사본을 잡도록 강제하는 방법이 있습니까?
[&](){ ... } // Capture by reference
vs.
[=](){ ... } // Capture copies
해결책
컴파일러가하는 일은 람다와 람다에서 캡처 한 변수를 컴파일러 생성 중첩 클래스로 끌어 당기는 것입니다.
편집 후 예제는 다음과 같이 보입니다.
class Program
{
delegate void Action();
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
DisplayClass1 displayClass1 = new DisplayClass1();
for (displayClass1.i = 0; displayClass1.i < 10; ++displayClass1.i )
actions.Add(new Action(displayClass1.Lambda));
foreach (Action a in actions)
a();
}
class DisplayClass1
{
int i;
void Lambda()
{
Console.WriteLine(i);
}
}
}
For Loop 내에서 사본을 만들어 컴파일러는 각 반복에서 다음과 같이 새 개체를 생성합니다.
for (int i = 0; i < 10; ++i)
{
DisplayClass1 displayClass1 = new DisplayClass1();
displayClass1.i = i;
actions.Add(new Action(displayClass1.Lambda));
}
다른 팁
내가 찾을 수있는 유일한 해결책은 먼저 로컬 사본을 만드는 것입니다.
for (int i = 0; i < 10; ++i)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
그러나 나는 For-loop 안에 사본을 넣는 이유를 이해하는 데 어려움을 겪고 있습니다. i
.
유일한 해결책은 Lambda 내에서 로컬 사본을 만들고 참조하는 것입니다. 클로저에서 액세스 할 때 C# (및 vb.net)의 모든 변수는 참조 시맨틱과 카피/값 의미를 갖습니다. 이 동작을 어느 언어로도 바꿀 방법이 없습니다.
참고 : 실제로 참조로 컴파일하지 않습니다. 컴파일러는 변수를 클로저 클래스로 들어 올리고 주어진 폐쇄 클래스 내부의 "I"의 "I"에 대한 액세스를 "I"로 리디렉션합니다. 그래도 참조 의미로 생각하는 것이 종종 더 쉽습니다.
람다 표현은 실제로 익명의 방법에 대한 구문 설탕 일뿐입니다.
즉, 당신이 실제로 찾고있는 것은 익명의 방법이 부모의 범위에서 로컬 변수를 사용하는 방법입니다.
다음은 이것을 설명하는 링크입니다. http://www.codeproject.com/kb/cs/insideanonymousmethods.aspx#4