在C#中的元素层次结构中排序问题

时间:2011-11-27 15:53:37

标签: c# icomparer

我一直在使用ASP.NET中的一个页面。此页面的行为与论坛完全相同。用户可以回复条目。回复表示为ItemReply。当用户回复某个项目时,ParentID将设置为用户正在响应的ItemReply的ID。

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的目的是用于基本确定从​​UI透视图缩进答复的距离。为了演示,想象一下具有以下层次结构:

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

出于某种原因,我的所有ItemReply元素的等级为1.我做错了什么?

谢谢!

1 个答案:

答案 0 :(得分:0)

  

出于某种原因,我的所有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永远不会使用其父级别的未初始化值。