С# рекурсивно получить позицию объекта

У меня есть класс, который ссылается на себя. IdModuloPai — это ключ, указывающий на родительский объект, а ModulosFilhos — дочерние объекты этого объекта.

У меня есть свойство Profundidade, которое рекурсивно вычисляет глубину этого объекта.

Еще одним важным свойством является Ordem. Он содержит желаемый порядок, определенный пользователем в этой области.

Id  Nome            IdModuloPai Ordem   Profundidade    OrdemGlobal
1   Root            [NULL]      0       0               0
2   Users           1           0       1               1
3   Administration  2           0       2               2
4   Logs            2           1       2               3
5   Customers       1           0       1               4
6   Orders          5           0       2               5

Посмотрите на эту примерную таблицу.

Я пытаюсь создать функцию, похожую на Profundidade, которая вычисляет свою глобальную позицию. Я пытаюсь получить последний столбец OrdemGlobal. Затем я могу заказать объекты с помощью OrdemGlobal, и они всегда будут отображаться одинаково в каждом нужном мне месте.

Исходя из этой таблицы, правильное положение

Root
    +Users
        +Administration
        +Logs
    +Customers
        +Orders

Посмотрите, что Администрация появляется перед Журналами, потому что у Администрации Ордем = 0, а у Журналов Ордем = 1.

Как я могу заархивировать желаемое поведение?

Код моего класса следует

public class ModuloModel
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public int Ordem { get; set; }
    public virtual int Profundidade { 
        get
        {
            return GetDepth(this);
        }
    }

    public int? IdModuloPai { get; set; }
    public virtual ModuloModel ModuloPai { get; set; }
    public virtual ICollection<ModuloModel> ModulosFilhos { get; set; }

    private int GetDepth(ModuloModel moduloModel)
    {
        if (moduloModel == null) return 0;
        if (moduloModel.IdModuloPai == null) return 0;
        return GetDepth(moduloModel.ModuloPai) + 1;
    }
}

EDIT: улучшенный вопрос

Я пробовал что-то вроде

    public virtual int OrdemGlobal
    {
        get
        {
            return GetGlobalOrder(this);
        }
    }        

    private int GetGlobalOrder(ModuloModel moduloModel)
    {
        if (moduloModel == null) return 0;
        if (moduloModel.ModuloPai == null) return 0;

        int smallerSiblings = moduloModel.ModuloPai.ModulosFilhos.Where(x => x.Ordem < moduloModel.Ordem).Count();
        return (GetGlobalOrder(moduloModel.ModuloPai) + smallerSiblings + 1;
    }

Но это сбивает с толку и не возвращает желаемую информацию.


person Andy Schmitt    schedule 10.11.2016    source источник
comment
Можете ли вы привести пример того, что возвращает GetGlobalOrder?   -  person Paul Stoner    schedule 10.11.2016


Ответы (2)


Вот IComparer<ModuloModel>, который сортируется в нужном вам порядке.

public class ModuloModelComparer : Comparer<ModuloModel>
{
    public override int Compare(ModuloModel x, ModuloModel y)
    {
        //They are the same node.
        if (x.Equals(y))
            return 0;

        //Cache the values so we don't need to do the GetDepth call extra times
        var xProfundidade = x.Profundidade;
        var yProfundidade = y.Profundidade;

        //Find the shared parent
        if (xProfundidade > yProfundidade)
        {
            //x is a child of y
            if (x.ModuloPai.Equals(y))
                return 1;
            return Compare(x.ModuloPai, y);
        }
        else if (yProfundidade > xProfundidade)
        {
            //y is a child of x
            if (x.Equals(y.ModuloPai))
                return -1;
            return Compare(x, y.ModuloPai);
        }
        else
        {
            //They both share a parent but are not the same node, just compare on Ordem.
            if (x.ModuloPai.Equals(y.ModuloPai))
                return x.Ordem.CompareTo(y.Ordem);

            //They are the same level but have diffrent parents, go up a layer
            return Compare(x.ModuloPai, y.ModuloPai);
        }
    }
}

Вот тестовая программа, которая его использует

class Test
{
    public static void Main()
    {

        var root = CreateModel(1, "Root", null, 0);
        var users = CreateModel(2, "Users", root, 0);
        var administration = CreateModel(3, "Administration", users, 0);
        var logs = CreateModel(4, "Logs", users, 1);
        var customers = CreateModel(5, "Customers", root, 0);
        var orders = CreateModel(6, "Orders", customers, 0);


        List<ModuloModel> list = new List<ModuloModel> {root, users, administration, logs, customers, orders};

        list.Sort(new ModuloModelComparer());

        foreach (var moduloModel in list)
        {
            Console.WriteLine(moduloModel.Nome);
        }
        Console.ReadLine();
    }

    private static ModuloModel CreateModel(int id, string Nome, ModuloModel moduloPai, int ordem)
    {
        var model = new ModuloModel {Id = id, Nome = Nome, IdModuloPai = moduloPai?.Id, ModuloPai = moduloPai, ModulosFilhos = new HashSet<ModuloModel>(), Ordem = ordem};
        moduloPai?.ModulosFilhos.Add(model);
        return model;
    }
}

Надеюсь, этого достаточно, чтобы направить вас на правильный путь.

person Scott Chamberlain    schedule 10.11.2016

Почему бы просто не вернуться

return this.Ordem;

Где совокупный корень? Класс обращается к самому себе, поэтому он должен знать, какое значение Ordem он имеет. Он ничего не знает о том, что над ним, только о своих детях.

person Ross Miller    schedule 10.11.2016