Monday, May 27, 2013

Closure 쓸 때 주의할 점

지난 포스트에 이어서...

var list = new List<int>(10);
var menu = new ToolStripMenuItem("메뉴");
for(int i=0; i<list.Count; i++) {
     var subMenu = new ToolStripMenuItem("메뉴 항목");
     subMenu.Click += ( (sender, args)=>{ subMenu_Click(sender, i); } ); // closure
}
void subMenu_Click(object sender, int idx)
{
     MessageBox.Show(string.Format("{0}이 클릭됨", idx));
}

예상되는 결과는? i번째 subMenu를 누르면 i가 출력되지 않는다.

다음과 같이 변수를 한 번 복사하는 게 해결책이다:

for(int i=0; i<list.Count; i++) {
     var subMenu = new ToolStripMenuItem("메뉴 항목");
   int j=i; // 이거면 되지 않을까 했는데 진짜 됐음-_-乃
     subMenu.Click += ( (sender, args)=>{ subMenu_Click(sender, j); } ); // closure
}

해결하고 나서 stackoverflow에 질문을 올렸는데

Google: passing parameter evenhandler value changes C#

이걸로 검색하니까 금방 나옴.

역시 원리는 안 찾아보고 하니까 이유는 모른다.

아래 링크에 이유가 있다고 하는데 읽기는 귀찮다.
http://stackoverflow.com/questions/2226510/closures-in-c-sharp-event-handler-delegates
http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop

No comments:

Post a Comment

창 핸들을 만드는 동안 오류가 발생했습니다

System.ComponentModel.Win32Exception was unhandled   MyForm w = new MyForm IntPtr handle = wnd.Handle;   // Exception occurs here class MyFo...