Вопрос
У меня есть TreeView, который представляет различные элементы фильтра для набора записей. Во время выполнения я устанавливаю тег каждого узла в тип функции 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");
так далее..
Затем, когда пользователь нажимает на узле, я просто передаю тег и использую его как предикат для получения моих данных:
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);
}
Проблема в том, что узлы, созданные динамически всеми, содержат один и тот же объект предиката (который, кажется, такой же предикат, созданный во время последней иетерации для поиска).
Я не совсем уверен, что здесь происходит. Есть идеи? Бесконечно благодарен!
Решение
Вы захватываете неружущую переменную, а именно 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);
}
Другие советы
(Func<MyRecordType, bool>)(p=> p.CreatedBy == user);
должно сработать.
Когда вы создаете функцию функции <>, это делает нет Храните текущее значение пользовательской переменной и, скорее работают на переменной, совместно используемой итерацией цикла. Он будет работать, когда вы создаете новую копию переменной внутри цикла.
Например, вместо:
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);
}