20-1217 Closure

최용국·2020년 12월 18일
0

기타

목록 보기
6/6

로컬 변수를 참조하는 무명메서드 또는 람다식

무명메서드나 람다식을 Closure라고 생각하면 안된다. 특정한 조건에서 Closure를 구현할 수 있다. 여기서 특정한 조건은 함수 바깥에 있는 로컬 변수를 참조할 때를 얘기한다. 아래 무명메서드의 Closure를 보면 이해가 될 것이다.

무명메서드 Closure

public void Foo()
{
	int i = 1; // 로컬 변수
	Action<string> action = delegate (string input)
	{
		Console.WriteLine($"{i} {input}");
	}

	action("Hello");
	// 1 Hello
}

Closure는 로컬 변수를 참조하고 있으므로 로컬 변수가 변하면 Closure 내부도 변한다. 이를 모르고 무명메서드와 람다식을 사용한다면 기댓값과 다른 결과를 맞이할 수 도 있다.

!!! 주의

public void Foo()
{
	int i = 1;
	Action<string> action = delegate (string input)
	{
		Console.WriteLine($"{i} {input}");
	}
	i = 2;

	action("Hello");
	// 기대하는 값이 1 Hello일 수도 있지만 그렇지 않다.
	// 출력 값: 2 Hello
}

아래의 결과는 어떻게 될까?

class Program
{
    public static List<int> Values = new List<int>() { 1, 6, 5, 3, 2 };
    static void Main(string[] args)
    {
        List<Action> sumAction = new List<Action>();
        for (int idx = 0; idx < Values.Count; idx++)
        {
            sumAction.Add(() => Console.WriteLine(idx + Values[idx]));
        }

        // Do Something

        foreach (var sum in sumAction)
        {
            sum();
        }

        Console.ReadLine();
    }
}

for문은 로컬 변수 idx를 Values.Count만큼 증가시킨 후 Values.Count와 비교하고 루프 문을 종료하게 될 텐데. 여기서 sumAction을 호출하게 된다면 idx가 배열 인덱스를 벗어난 상태이기 때문에 System.ArgumentOutOfRangeException를 보게 될 것이다.

Closure는 컴파일러에 의해 구현된다. 컴파일러는 Nested Class를 활용해 메서드에 변형을 주는데 자세한 내용은 아래를 참고하고 이번 섹션에서는 생략한다.

C# Closure 이해하기 - C# 프로그래밍 배우기 (Learn C# Programming)

profile
코딩합시다.

0개의 댓글