1

我有以下简化类:

public class BaseContainer
{
    public BaseContainer()
    {
        Children = new ObservableCollection<BaseContainer>();
    }
    public ObservableCollection<BaseContainer> Children { get; set; }
}

public class ItemA : BaseContainer
{
    public ItemA()
    {
        base.Children.Add(new ItemB() { ItemBName = "bb" });
        base.Children.Add(new ItemA() { ItemAName = "ab" });
        base.Children.Add(new ItemB() { ItemBName = "ba" });
        base.Children.Add(new ItemA() { ItemAName = "aa" });
    }
    public string ItemAName { get; set; }
}

public class ItemB : BaseContainer
{
    public string ItemBName { get; set; }
}

我正在尝试根据两个条件对我的 ItemA.Children 集合进行排序:

  1. 所有项目 A 必须在集合中排在第一位
  2. 项目 A 应按 ItemAName 排序
  3. 项目 B 应按 ItemBName 排序

所以在排序之后我会期待这样的事情:

  • ItemA - ItemAName = "aa"
  • ItemA - ItemAName = "ab"
  • ItemB - ItemBName = "ba"
  • ItemB - ItemBName = "bb"

关于如何做到这一点的任何想法?

我能够按类类型名称排序:

        List<BaseContainer> temp = base.Children.ToList();
        temp.Sort((x, y) => string.Compare(x.GetType().Name, y.GetType().Name));
        base.Children.Clear();
        base.Children.AddRange(temp);

但是名称没有排序...

谢谢!

4

3 回答 3

2
var result = temp.OrderBy(x => x.GetType().Name).ThenBy(x => GetPropValue(x));

string GetPropValue(object o)
{
    Type t = o.GetType();
    var p = t.GetProperty("ItemAName");
    if (p != null)
    {
        return (string)p.GetValue(o, null);
    }
    p = t.GetProperty("ItemBName");
    return (string)p.GetValue(o, null);
}
于 2012-12-05T17:23:30.677 回答
1

这将获取所有 A,按 AName 排序,然后与所有 B 按 B 名称排序。

var result = Children.OfType<ItemA>().OrderBy(a => a.ItemAName).Cast<Base>()
    .Concat(Children.OfType<ItemB>().OrderBy(b => b.ItemBName));

我不确定这是我会采用的设计......您可能会考虑在基类中添加一些东西以促进这种排序。

于 2012-12-05T17:30:50.400 回答
1

您通过指定来初始化项目ItemName,但既不也不BaseContainer定义这样的属性。ItemAItemB

声明ItemName in the base classBaseContainer`。项目类自动继承此属性,无需在此处重新定义此类字段。

public class BaseContainer
{
    public string ItemName { get; set; }

    ...
}

public class ItemA : BaseContainer
{
    // Inherits ItemName 
}

public class ItemB : BaseContainer
{
    // Inherits ItemName 
}

现在像这样对列表进行排序:

var result = base.Children
    .OrderBy(b => b.GetType().Name)
    .ThenBy(b => b.ItemName);

并且在排序之前无需将其存储到临时列表中。结果是一个IEnumerable<BaseContainer>. .ToList()如果要将结果存储为列表,可以附加 a 。

var result = base.Children
    .OrderBy(b => b.GetType().Name)
    .ThenBy(b => b.ItemName)
    .ToList();

更新

根据您的评论,您没有共同ItemName财产。为什么?你真的应该有一个。重构你的类。如果由于某种原因您不想要ItemNamein BaseContainer,请创建一个抽象基类Item或让项目实现一个公共接口。

public abstract class Item : BaseContainer
{
    public string ItemName { get; set; }
}

public class ItemA : Item
{
}

public class ItemB : Item
{
}

或者

public interface IItem
{
    string ItemName { get; set; }
}

public class ItemA : BaseContainer, IItem
{
    public string ItemName { get; set; }
}

public class ItemB : BaseContainer, IItem
{
    public string ItemName { get; set; }
}

现在你可以像这样排序

var result = base.Children
    .OfType<Item> // or .OfType<IItem>
    .OrderBy(i => i.GetType().Name)
    .ThenBy(i => i.ItemName);

结果将是IEnumerable<Item>or IEnumerable<IItem>


另一个选择是覆盖ToString每个对象继承自的方法Syste.Object

public class ItemA : BaseContainer
{
    public string ItemAName { get; set; }

    public override string ToString()
    {
        return "ItemA: " + ItemAName;
    }
}

这简化了排序,因为两个条件(按类型排序和按名称排序)都可以一步完成。该字符串也将显示在列表框、组合框等中。

var result = base.Children
    .OrderBy(b => b.ToString());

如果这不可能,请为此创建并实现一个接口:

public interface ISortable
{
    string SortString { get; }
}

public class ItemA : BaseContainer, ISortable
{
    public string ItemAName { get; set; }

    public string SortString { get { return "ItemA: " + ItemAName; } }
}

并排序

var result = base.Children
    .OfType<ISortable> 
    .OrderBy(b => b.SortString);
于 2012-12-05T17:31:11.530 回答