람다 변수 캡처(Capture)
람다를 다루다 보면 변수를 캡처하는 상황을 맞이하게 될 것이다.
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 10; ++i)
{
actions.Add(() => Console.WriteLine(i));
}
foreach (var a in actions)
{
a.Invoke();
}
// 기대하던 출력: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
// 실제 출력: 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
}
}
위의 코드를 작성한 개발자의 기댓값과 실제값은 다르다. 왜냐면, C# 컴파일러는 i 값에 대한 변수를 다음과 같이 임시 생성한 클래스의 변수로 대체해 버리기 때문이다.
using System;
using System.Collections.Generic;
public class [임시클래스]
{
public int _i;
public void _f()
{
Console.WriteLine(_i);
}
}
class Program
{
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
[임시클래스] _var = new [임시클래스]();
for (_var._i = 0; _var._i < 10; ++_var._i)
{
actions.Add(_var._f);
}
foreach (Action a in actions)
{
a.Invoke();
}
}
}
(i를 캡처하기 위해서 만들어진 임시 클래스)
우리가 원하는 바를 이루기 위해서는 이렇게 코드를 작성해야 한다.
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 10; ++i)
{
int v = i;
actions.Add(() => Console.WriteLine(v));
}
foreach (Action a in actions)
{
a.Invoke();
}
}
}
이렇게 되면 C# 컴파일러는 i가 아닌 v 변숫값을 캡처하기 위해 다음과 같은 식으로 for 루프 내에서 임시클래스를 생성하게 된다.
using System;
using System.Collections.Generic;
public class [임시클래스]
{
public int _v;
public void _f()
{
Console.WriteLine(_i);
}
}
class Program
{
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 10; ++i)
{
[임시클래스] _var = new [임시클래스]();
_var._v = i;
actions.Add(_var._f);
}
foreach (Action a in actions)
{
a.Invoke();
}
}
}
이전 포스팅에 있는 볼링 점수 계산기 코드에서도 비슷한 코드를 발견할 수 있다.
정리하자면 결국 변수를 캡처할 때 중요한 건 범위(Scope)라는 걸 알 수 있다.
해당 규칙을 잘 숙지해서 항상 원하는 결과가 나오도록 코딩해 보자.
출처
'프로그래밍 > C#' 카테고리의 다른 글
C# 지연 평가(lazy evaluation)에 대해서 (0) | 2024.02.13 |
---|---|
C# Virtual vs Abstract (0) | 2024.02.03 |
C# 볼링 점수 계산기(Bowling Score Calculator) (2) | 2024.01.19 |
C# 문자열 정렬하기 (0) | 2024.01.15 |
C# Call by value와 Call by reference에 대해서 (0) | 2024.01.12 |
댓글