LINQ,匿名类型和闭包问题

我有一段代码使用LINQ过滤列表,创建匿名类型的实例列表,并为每个实例分配一个事件处理程序:

// Select every linear expression and create a menu item from it var items = from expr in expressionList.Expressions where expr.Type == ExpressionType.Linear let stdExpr = (StandardExpression)expr select new { Menu = new ToolStripMenuItem(stdExpr.Expression), // string stdExpr.Slot // int }; // Wire a Click event handler to each menu to set the tracked line foreach (var item in items) { item.Menu.Click += (s, e) => graph.SetTrackedLine(item.Slot); menuTrackLineWithMouse.DropDownItems.Add(item.Menu); } 

这很有效,因为事件处理程序有线并且菜单正确添加。 单击菜单项时会出现问题,并触发处理程序。 无论哪个菜单项触发了处理程序,只有最后一个传递给SetTrackedLine

一个例子是如果我有两个菜单,“sin(x)”,插槽0和“cos(x)”,插槽1 ,两个Click事件都将1传递给SetTrackedLine ,无论“sin(x)”是点击或“cos(x)”是。

我的问题是,为什么会发生这种情况? 不应该item.Slot引用匿名类型的每个单独的实例?

谢谢。

你正在关闭循环变量 。 具体问题在于:

 (s, e) => graph.SetTrackedLine(item.Slot) ^^^^ 

使用的item的值将是运行 lambda表达式时的当前值,而不是创建它时的值。 这是C#的“陷阱”和常见错误。

试试这个:

 foreach (var item in items) { var item2 = item; item2.Menu.Click += (s, e) => graph.SetTrackedLine(item2.Slot); menuTrackLineWithMouse.DropDownItems.Add(item2.Menu); }