3 c# linq closures anonymous-types
我有一段代码使用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);
}
Run Code Online (Sandbox Code Playgroud)
这很有效,因为事件处理程序有线并且菜单被正确添加.单击菜单项时会出现问题,并触发处理程序.无论哪个菜单项触发了处理程序,只传递最后一个SetTrackedLine.
一个例子是,如果我有两个菜单,"sin(x)",带槽0,"cos(x)",带槽1,两个Click事件都传递1给SetTrackedLine,无论是否点击"sin(x)"或"cos( x)"是.
我的问题是,为什么会发生这种情况?不应该item.Slot引用匿名类型的每个单独实例?
谢谢.
您正在关闭循环变量.具体问题在于:
(s, e) => graph.SetTrackedLine(item.Slot)
^^^^
Run Code Online (Sandbox Code Playgroud)
itemused 的值将是lambda表达式运行时的当前值,而不是创建它时的值.这是C#的"陷阱"和常见错误.
试试这个:
foreach (var item in items)
{
var item2 = item;
item2.Menu.Click += (s, e) => graph.SetTrackedLine(item2.Slot);
menuTrackLineWithMouse.DropDownItems.Add(item2.Menu);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
940 次 |
| 最近记录: |