Unity의 UI Button에 onClick 이벤트를 반복문 내에서 동적으로 할당하여 사용할 때 발생한 문제.

 

문제 상황 발생의 소스 코드

    private void Test()
    {
        List<Button> buttonList = new List<Button>();
        int max = 3;
     
        for (int i = 0; i < max; i++)
        {
            GameObject buttonObject = new GameObject("Button_" + i);
            buttonList.Add(buttonObject.AddComponent<Button>());
        }

        for (int i = 0; i < max; i++)
        {
            Debug.Log(buttonList[i].name + "\tAdd OnClick Event");
            buttonList[i].onClick.AddListener(() =>
            {
                Debug.Log(i);
            });
        }

        for (int i = 0; i < buttonList.Count; i++)
        {
            buttonList[i].onClick.Invoke();
        }
    }

위의 소스 코드로 실행했을 때의 결과

원하는 결과는 아래 3개의 Log에서 0, 1, 2 순서로 출력되어야 하는데 반복문에서 사용된 변수의 값의 최종값만 출력하게 되는 것 같아보였다. 이러한 상황에서 문제가 되는 상황은 List나 Array에 해당 값을 넣어서 접근하게 되면 out of range 가 일어나는 상황이다.

 

변경된 소스 코드

        //for (int i = 0; i < max; i++)
        //{
        //    Debug.Log(buttonList[i].name + "\tAdd OnClick Event");
        //    buttonList[i].onClick.AddListener(() =>
        //    {
        //        Debug.Log(i);
        //    });
        //}

        for (int i = 0; i < max; i++)
        {
            int index = i;
            Debug.Log(buttonList[i].name + "\tAdd OnClick Event");
            buttonList[i].onClick.AddListener(() =>
            {
                Debug.Log(index);
            });
        }

소스 코드를 변경한 이후의 결과

 

for 문에의 증감에 사용된 변수를 다시 for 문 안에서 지역 변수로 할당하여 사용하면 문제가 없었다.

 

C# 람다 식을 사용하면 컴파일 시에 람다 함수내의 변수와 코드를  임시 클래스로 만들어서 사용한다고 한다.

 

즉, for 문에서 선언된 int i 는 임시 클래스의 멤버 변수로 선언 되고 해당 변수를 for 문 내에서 참조하여 사용하기 때문에 최종적으로 Log를 찍는 순간에는 for문의 증감문이 전부 적용되어 int i 는 3이 되었고 해당 변수를 동일하게 참조하고 있기 때문에 3의 값으로만 출력되는 것이다.

 

 

참조: https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#capture-of-outer-variables-and-variable-scope-in-lambda-expressions

 

람다 식 - C# 프로그래밍 가이드

람다 식(C# 프로그래밍 가이드)Lambda expressions (C# Programming Guide) 이 문서의 내용 --> 람다 식은 다음 두 형식의 식입니다.A lambda expression is an expression of any of the following two forms: 식이 본문으로 포함된

docs.microsoft.com

 

 

 

Posted by Heon_Dev
,