Проблема сортировки в иерархии элементов в C # - PullRequest
1 голос
/ 27 ноября 2011

Я работал над страницей в ASP.NET.Эта страница ведет себя как форум.Пользователь может отвечать на записи.Ответ представляется как ItemReply.Когда пользователь отвечает на элемент, ParentID устанавливается на идентификатор ItemReply, на который отвечает пользователь.

public class ItemReply
{
    public Guid ID { get; set; }    
    public Guid? ParentID { get; set; }
    public int Level { get; set; }    
    public string Remarks { get; set; }    
    public DateTime CreatedOn { get; set; }    
    public string CreatedBy { get; set; }

    public ItemReply(DataRow row)
    {
        ID = GetGuidFromRow(row, "ID", 0);
        ParentID = GetGuidFromRow(row, "ParentID", null);
        Remarks = GetStringFromRow(row, "Remarks", string.Empty);
        Level = 1;

        CreatedOn = GetDateTimeFromRow(row, "CreatedOn", DateTime.UtcNow);
        CreatedBy = GetStringFromRow(row, "CreatedBy", string.Empty);
    }
}

public class ItemComparer : IComparer<ItemReply>
{
    IDictionary<Guid, ItemReply> itemLookup;
    public ReplyComparer(IEnumerable<ItemReply> list)
    {
        itemLookup = list.ToDictionary(item => item.ID);
        foreach (var item in list)
            SetLevel(item);
    }

    public int SetLevel(ItemReplyitem)
    {
        if (item.Level == 0 && item.ParentID.HasValue)
            item.Level = 1 + itemLookup[item.ParentID.Value].Level;
        return item.Level;
    }

    public int Compare(ItemReply x, ItemReply y)
    {
        // see if x is a child of y
        while (x.Level > y.Level)
        {
            if (x.ParentID == y.ID)
                return 1;
            x = itemLookup[x.ParentID.Value];
        }

        // see if y is a child of x
        while (y.Level > x.Level)
        {
            if (y.ParentID == x.ID)
                return -1;
            y = itemLookup[y.ParentID.Value];
        }

        // x and y are not parent-child, so find common ancestor
        while (x.ParentID != y.ParentID)
        {
            if (x.ParentID.HasValue)
                x = itemLookup[x.ParentID.Value];
            if (y.ParentID.HasValue)
                y = itemLookup[y.ParentID.Value];
        }

        // compare createDate of children of common ancestor
        return x.CreatedOn.CompareTo(y.CreatedOn);
    }
}

Этот код в основном выполняется с помощью:

List<ItemReply> replies = GetRepliesFromDataSource();
replies.Sort(new ReplyComparer(replies));

порядок и иерархия, кажется, работают должным образом.Однако метод SetLevel работает неправильно.Назначение SetLevel используется для определения того, как далеко отступать ответ с точки зрения пользовательского интерфейса.Для демонстрации представьте себе следующую иерархию:

- Root
-- Child 1
--- Grandchild A
--- Grandchild B
-- Child 2      
--- Grandchild C

По какой-то причине все мои элементы ItemReply имеют уровень 1. Что я делаю не так?

Спасибо!

1 Ответ

0 голосов
/ 27 ноября 2011

По какой-то причине все мои элементы ItemReply имеют уровень 1. Что я делаю не так?

Ваш SetLevel метод неверен, так как он опирается на определенныйПорядок перечисления для его правильности - родители должны быть обработаны раньше своих детей.К сожалению, ничто не говорит о том, что список, который у вас есть, гарантирует такой порядок.

Что если родительский элемент не имеет своего уровня, установленного при вызове SetLevel?Тогда ваш метод назначит Level 1 + 0 вместо 1 + Parent's Actual Level.

Это легко исправить с помощью рекурсивного вызова:

public int SetLevel(ItemReply item)
{
    if (item.Level == 0 && item.ParentID.HasValue)
        item.Level = 1 + SetLevel(itemLookup[item.ParentID.Value]);

    return item.Level;
}

Это гарантирует, что SetLevel никогда не будет работать с неинициализированным значением для уровня его родителя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...