C#이나 Javascript 두 언어 다 개인적으로 Lambda 식을 많이 사용하는데요. 최근 for loop 안에서 lambda 식을 사용 했을 때 예상치 못한 결과가 계속 나와서 충격을 받았던 경험이 있었습니다. 그 경험을 공유하려고 합니다.
예시 상황은, Button들이 array에 담겨져 있고 for loop를 돌면서 이벤트를 등록했습니다.
using UnityEngine;
using UnityEngine.UI;
namespace LambdaInForLoop
{
public class ButtonManager : MonoBehaviour
{
[SerializeField] private Button[] buttons;
void Start()
{
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].onClick.AddListener(() =>
{
print(i);
});
}
}
}
}
이렇게 했을 때 각 버튼을 눌렀을 때 예상 결과는 각 순서에 맞는 숫자가 print 되어야 할텐데요. (예를 들어서 첫번째 버튼은 0, 두번째는 1, 세번째는 2,... ). 그런데 충격적인 결과가 나왔습니다. 모든 버튼이 같은 수를 계속 print 했습니다. 그리고 그 수는 buttons.Length 와 같았지요. 그래서 등록된 버튼이 3개였으면 모든 버튼이 3을 print 했습니다.
인터넷에 검색해 보니 for loop의 iteration variable을 lambda 식에 그대로 사용 했을 시 value type이 아닌 reference 타입 처럼 값을 capture 해두고 있다가 사용된다고 하더라구요. 그래서 for loop에서 제일 마지막 loop에서 i++되었을 때 값이 capture 되어있다가 버튼이 클릭 되었을 때 buttons.Length 값이 print 되었습니다.
그렇다면 이걸 어떻게 해결할 수 있을까요? 간단합니다. for loop안에 local variable을 하나 두고 복사 해서 사용하면 된다고 합니다.
using UnityEngine;
using UnityEngine.UI;
namespace LambdaInForLoop
{
public class ButtonManager : MonoBehaviour
{
[SerializeField] private Button[] buttons;
void Start()
{
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].onClick.AddListener(() =>
{
int copy = i;
print(copy);
});
}
}
}
}
위 코드에서 int copy = i; 부분이 바로 복사를 하는 부분입니다.
혹시 Lambda 식을 자주 사용하시는 분들은 꼭 알아두셔야 할 내용인 것 같네요~
'Unity & C#' 카테고리의 다른 글
CustomEditor 활용하기 - bool 값으로 variable 보여주기 (0) | 2022.04.03 |
---|---|
[유니티] 왜 이제 알았을까 요놈 Animation Curve (2) | 2021.12.16 |
[유니티] Unity Remote 5 활용하여 모바일 개발하기 (0) | 2021.12.02 |
[C# 문법] Reference Type 과 Value Type의 차이점 (0) | 2021.11.14 |
[유니티 C#] Json 저장 & 불러오기 너무 쉽게 구현하기 (3) | 2021.11.12 |