Вопрос

У меня есть 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);
        }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top