问题LINQ,匿名类型,和封闭 [英] Problem with LINQ, anonymous types, and closures

查看:117
本文介绍了问题LINQ,匿名类型,和封闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一块能过滤使用LINQ列表代码,创建一个匿名类型的实例的列表,以及事件处理程序分配给每个实例

I have a piece of code that filters a list using LINQ, creates a list of instances of an anonymous type, and assigns an event handler to each instance:

// 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

This works well in that the event handlers get wired and the menus get added correctly. The problem comes when the menu item is clicked, and the handler is fired. No matter what menu item fired the handler, only the last one is ever passed to SetTrackedLine.

一个例子是如果我有两个菜单,罪(X),与插槽 0 和COS(X),与插槽 1 ,无论点击事件传递 1 SetTrackedLine ,不管罪(X)被点击或COS(X)了。

An example is if I have two menus, "sin(x)", with slot 0, and "cos(x)", with slot 1, both Click events pass 1 to SetTrackedLine, no matter if "sin(x)" was clicked or "cos(x)" was.

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

My question is, why does this happen? Shouldn't item.Slot refer to each separate instance of the anonymous type?

感谢。

推荐答案

您是的关闭了循环变量。这个问题特别是在这里:

You are closing over the loop variable. The problem specifically is here:

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



<$的值C $ C>项目运行,而不是它有当它是值>的创建的的。这是一个C的疑难杂症#和一个常见的​​错误

The value of item used will be the current value when the lambda expression is run, not the value it had when it was created. This is a "gotcha" of C# and a common error.

试试这个:

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

这篇关于问题LINQ,匿名类型,和封闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆