bugMaker-237 Ответов: 1

Почему предикат неверно интерпретирует значения параметров при вызове рекурсивной функции


Я пытаюсь создать расширенный элемент управления treeview, наследующий существующий элемент управления winform TreeView. Создал а Load() функция в классе TreeViewEx. В этой функции источник данных зацикливается в foreach. Этот foreach затем вызывает Where() метод расширения на циклическом источнике данных, передающий ему метод Methode (который принимает в качестве параметра текущий элемент), возвращающий предикат. Этот предикат неверно интерпретирует переданное ему значение параметра. Похоже, он использует предыдущие значения параметров.

значение arg в методе перед возвращением предиката => Изображение[^]

значение arg, когда отладчик вводит предикат => Изображение[^]

Что я уже пробовал:

Изначально я думал, что такое поведение связано с тем, что я перебираю перечисляемый, а не список, поэтому я меняю различные перечисляемые объекты на список, но ничего не изменилось. Также попытался установить возвращаемый предикат, но ничего не получилось.

Функция нагрузки :


public Func<T, Func<T, bool>> GetChildrenPredicate { get; set; }
.
.
.
public virtual void Load(List<T> dataSource = null)
{
    try
    {
        if (CreateNode == null)
        {
            OnError?.Invoke(this, new ArgumentNullException("CreateNode"));
            return;
        }
        if (GetParentKey == null)
        {
            OnError?.Invoke(this, new ArgumentNullException("GetParentKey"));
            return;
        }
        if (GetChildrenPredicate == null)
        {
            OnError?.Invoke(this, new ArgumentNullException("GetChildrenPredicate"));
            return;
        }

        var finalDataSource = dataSource ?? DataSource;

        TreeNode node = null;
        BeginUpdate();
        foreach (var item in finalDataSource)
        {
            node = CreateNode(item);
            node.Tag = item;

            if (this.Nodes.Find(node.Name, true).Count() == 0)
            {
                var n = this.Nodes.Find(this.GetParentKey(item), true).FirstOrDefault() as TreeNode;

                if (n == null)
                {
                    this.Nodes.Add(node);
                }
                else
                {
                    n.Nodes.Add(node);
                }

                List<T> children = finalDataSource
                                  .ToList()                                   
                                  .Where(this.GetChildrenPredicate(item))
                                  .ToList(); //this.GetChildrenPredicate is
                                //the property func generating the 
                                //predicate set by a different class

                if (children.Count() > 0)
                {
                    // Recursively call this function for all childRows
                    Load(children);
                }

            }
        }
        EndUpdate();
    }
    catch (Exception ex)
    {
        OnError?.Invoke(this, ex);
    }
}


GetChildrenPredicate :

private Func<ORM.DataModels.Menu, bool> GetChildrenPredicate(ORM.DataModels.Menu arg)
{

    return (ORM.DataModels.Menu m) =>
    (m.Lepere == arg.Codmen) ||
    (m.Lepere == null && arg.Codmen == "_" + m.Niveau);
}

Gerry Schmitz

Я создаю свои собственные пользовательские древовидные представления (WPF, UWP), используя отсортированный список элементов, listview, level # и около 30 строк разнесенного кода.

Я бы сказал, что ваш чересчур спроектирован; предполагая, что он когда-либо работает и может быть поддержан.

bugMaker-237

Мой treeview находится в winform и является универсальным. Таким образом, он полагается на методы exteranl и события, установленные контроллером. Если вы считаете, что это можно улучшить, я готов выслушать любое предложение.

1 Ответов

Рейтинг:
8

bugMaker-237

Хорошо. Я нашел решение. На самом деле я не понимал, что `finalDataSource` переопределяется при каждом вызове `Load()`. Я был сосредоточен только на странном поведении предиката. просто нужно было использовать глобальное свойство DataSource, определенное в классе.


List<T> children = this.DataSource.Where(this.GetChildrenPredicate(item)); //<= changed local variable finalDataSource to the defined property this.DataSource