我有一个树视图,它表示一组记录的不同过滤项。在运行时,我将每个节点的标记设置为Func类型。例如:
myTreeView.Nodes.Add(New TreeNode("Node1"));
myTreeView.Nodes["Node1"].Tag = New Func<MyRecordType, bool>(p=> p.Title == "test 1");
myTreeView.Nodes.Add(New TreeNode("Node2"));
myTreeView.Nodes["Node2"].Tag = New Func<MyRecordType, bool>(p=> p.Title == "test 2");
等。
然后,当用户点击该节点时,我只是传递Tag并将其用作获取数据的谓词:
gridView.DataSource = populateData(nodeClicked.Tag as Func<MyRecordType, bool>);
private MyRecordType[] populateData(Func<MyRecordType, bool> predicate)
{
MyRecordType[] records;
if(predicate == null)
records = MyRecords.ToArray();
else
records = MyRecords.Where(predicate).ToArray();
return records;
}
这一切都很有效,但我添加了一些基于一组记录创建节点的代码。它看起来像这样:
var users = DB.MyRecords.OrderBy(o=> o.CreatedBy).Select(s=> s.CreatedBy).Distinct();
foreach(var user in users) {
var node = new TreeNode("Node" + user, user);
node.Tag = new Func<MyRecordType, bool>(p=> p.CreatedBy == user);
MyTreeView.Nodes.Add(node);
}
问题在于动态创建的节点都包含相同的谓词对象(它似乎与上一次forearch迭代期间创建的谓词相同)。
我不确定这里发生了什么。任何的想法?万分感谢!
答案 0 :(得分:2)
您正在捕获非本地变量,即user
。
在循环内创建一个临时文件并改为引用它。
示例:
foreach(var user in users) {
var u = user;
var node = new TreeNode("Node" + user, user);
node.Tag = new Func<MyRecordType, bool>(p=> p.CreatedBy == u);
MyTreeView.Nodes.Add(node);
}
答案 1 :(得分:0)
(Func<MyRecordType, bool>)(p=> p.CreatedBy == user);
应该有用。
答案 2 :(得分:0)
创建Func&lt;&gt;时对象,不存储用户变量的当前值,而是对循环迭代共享的变量进行操作。如果你在循环中创建变量的新副本,它将会工作。
,例如,而不是:
foreach (string s in new string[] { "1", "2", "3" })
funcs.Add(() => s);
使用
foreach (string s in new string[] { "1", "2", "3" })
{
string s1 = s;
funcs.Add(() => s1);
}