如何使用可选属性顺序按对象中的属性对List <t>进行排序

时间:2018-09-18 18:14:51

标签: c# list sorting generics

假设我有一个基类和两个派生类。

public abstract class BaseClass 
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string Owner { get; set; }

    public DateTime DateAdded { get; set; }
}

public class Foo : BaseClass
{
    [CustomAttr(Order = 2)]
    public string Country { get; set; }

    [CustomAttr(Order = 5)]
    public decimal Amount { get; set; }

    public string Other { get; set; }
}

public class Bar : BaseClass
{
    [CustomAttr(Order = 3)]
    public string Organization { get; set; }

    [CustomAttr(Order = 1)]
    public string Keywords { get; set; }
}

默认情况下,属性的顺序基于在类中声明属性的方式,因此如果在BaseClass中(因为没有[CustomAttr(Order = n),则假定这是正确的顺序)。

现在,由于在两个派生类中,有一个定义的自定义属性,该属性将标识行为应按以下顺序排序的属性顺序:

  1. 编号
  2. 国家
  3. 名称
  4. 说明
  5. 金额
  6. 所有者
  7. DateAdded
  8. 其他

因此,将CustomAttr[(Order = n)]的对象置于其财产顺序,对于那些没有Bar的对象,我们假定它们处于适当的顺序。如果我使用List<T>类,这也应该具有类似的行为。

这种情况的用例是,我需要在CustomAttr[(Order = n)]中具有正确的类属性顺序,以便在excel文件中具有正确的列顺序。

我要做的是我必须在所有属性中添加{{1}}才能对它们进行排序,但这是一件繁琐的事情,如果您尝试更改其中一个属性,则需要更改所有属性的顺序财产顺序。

有什么办法可以做到这一点?

3 个答案:

答案 0 :(得分:1)

您可以使用反射按声明的顺序读取类的所有属性的名称。然后,您可以在逻辑中进行详细说明,并对字段进行相应的排序。

尝试以下操作:

PropertyInfo[] propertyInfos = typeof(Bar).GetProperties();
foreach (var propInfo in propertyInfos)
    Console.WriteLine(propInfo.Name);

这将写入Bar类中的所有属性(这只是一个示例,您可以将其替换为任何类),包括继承自其超类(BaseClass)的属性。预期输出:

Organization
Keywords
Id
Name
Description
Owner
DateAdded

请注意,尽管此方法首先列出了该类的属性,然后在列出每个超类的层次结构中向上移动(这就是Bar的成员在BaseClass的成员之前被列出的原因) )。您可以进一步详细说明代码,以根据需要更改顺序。

以下(未优化的)代码首先创建从基类到给定T类的所有给定类层次结构的列表。之后,对每个类进行迭代,仅发现每个类中定义的属性(我通过GetProperties()方法传递了一个参数,指出我只想要 public 实例/非静态在我当前正在咨询的特定课程上声明)。

private static void ListAllOrderedPropertiesOfType(Type targetType)
{
    // Generate a list containing the whole hierarchy of classes, from the base type to the type T
    var typesList = new List<Type>();
    for (Type t = targetType; t != typeof(Object); t = t.BaseType)
        typesList.Insert(0, t);

    // Iterate from the base type to type T, printing the properties defined for each of the types
    foreach (Type t in typesList)
    {
        PropertyInfo[] propertyInfos = t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        foreach (var propInfo in propertyInfos)
            Console.WriteLine(propInfo.Name);
    }
}

因此,如果您想了解类型Bar的所有属性(从最顶层的基类到Bar类排序),可以这样调用该方法:

ListAllOrderedPropertiesOfType(typeof(Bar));

预期的输出将是以下顺序的属性:

Id
Name
Description
Owner
DateAdded
Organization
Keywords

这样,您就知道字段的声明顺序及其自定义顺序(通过CustomAttr属性)。现在,您可以实现一种排序方法,根据需要根据字段的声明顺序和CustomAttr顺序对字段进行排序。

但是我想这超出了我的回答范围(它旨在向您展示如何获得从基本类到任何给定特定类的属性声明的顺序)。

答案 1 :(得分:1)

I created a generic solution by reading your attribute and creating a comparer what will compare in the order of your attribute order. in the contructor of the comparer I am reading over reflection your attributes. While comparing I take one property after the other and when equal (zero), I go to the next. The logic works also with inheritance, so even on the base class you can have CustomAttr.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public class CustomAttr : Attribute
{
    public CustomAttr():base()
        {}

    public CustomAttr(int Order)
    {
        this.Order = Order;
    }
    public int Order {get ; set ; }

}
public abstract class BaseClass
{
    public int Id { get; set; }

    [CustomAttr(Order = 20)]
    public string Name { get; set; }

    public string Description { get; set; }

    public string Owner { get; set; }

    public DateTime DateAdded { get; set; }
}

public class Foo : BaseClass
{
    [CustomAttr(Order = 2)]
    public string Country { get; set; }

    [CustomAttr(Order = 5)]
    public decimal Amount { get; set; }

    public string Other { get; set; }
}

public class Bar : BaseClass
{
    [CustomAttr(Order = 3)]
    public string Organization { get; set; }

    [CustomAttr(Order = 1)]
    public string Keywords { get; set; }
}
class app
{


    static void Main()
    {
        List<Bar> listToOrder = new List<Bar>();
        listToOrder.Add(new Bar() { Id = 5, Keywords = "Hello", Organization = "Arlando" });
        listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" , Name = "Deep"});
    listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta", Name = "Inherit" });
    listToOrder.Add(new Bar() { Id = 1, Keywords = "Muppet", Organization = "Coke" });
        listToOrder.Add(new Bar() { Id = 6, Keywords = "Grumpy", Organization = "Snow" });
        listToOrder.Add(new Bar() { Id = 9, Keywords = "Johny", Organization = "White" });
        listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Bruno" });
        listToOrder.Add(new Bar() { Id = 12, Keywords = "Table", Organization = "Fuelta" });
        listToOrder.Add(new Bar() { Id = 7, Keywords = "Set", Organization = "Voltra" });
        listToOrder.Add(new Bar() { Id = 45, Keywords = "Brr", Organization = "Elvis" });
        listToOrder.Add(new Bar() { Id = 15, Keywords = "Tsss", Organization = "Marion" });

        OrderComparer<Bar> myOrder = new OrderComparer<Bar>();
        listToOrder.Sort(myOrder);

        foreach (Bar oneBar in listToOrder)
        {
            Console.WriteLine(oneBar.Id + " " + oneBar.Keywords + " " + oneBar.Organization);
        }

        Console.ReadKey();
    }

    private class OrderComparer<T> : IComparer<T>
    {
        SortedList<int, PropertyInfo> sortOrder = new SortedList<int, PropertyInfo>();

        public OrderComparer()
        {
            Type objType = typeof(T);
            foreach (PropertyInfo oneProp in objType.GetProperties())
            {
                CustomAttr customOrder = (CustomAttr) oneProp.GetCustomAttribute(typeof(CustomAttr), true);
                if (customOrder == null) continue;
                sortOrder.Add(customOrder.Order, oneProp);
            }
        }
        public int Compare(T x, T y)
        {
            Type objType = typeof(T);
            int result = 0;
            int i = 0;

            while (result == 0 && i < sortOrder.Count)
            {
                result = ((IComparable)sortOrder.ElementAt(i).Value.GetValue(x)).CompareTo(sortOrder.ElementAt(i).Value.GetValue(y));
                i++;
            }

            return result;
        }
    }
}

答案 2 :(得分:-1)

有关使用List与system.Linq的订单的信息,请参见此示例

class Program
{

    class test
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public string Description { get; set; }

        public string Owner { get; set; }

        public DateTime DateAdded { get; set; }
    }
    static void Main(string[] args)
    {


        List<test> listOrder = new List<test>();
        listOrder.Add(new test() { Id = 1, Name = "john", Description = "test", Owner = "test", DateAdded = DateTime.Now });
        listOrder.Add(new test() { Id = 1, Name = "max", Description = "test1", Owner = "test1", DateAdded = DateTime.Now });
        listOrder.Add(new test() { Id = 1, Name = "phil", Description = "test2", Owner = "test2", DateAdded = DateTime.Now });

        List<test> sortbyName = listOrder.OrderBy(item => item.Name).ToList();

        List<test> sortbyDescription = listOrder.OrderBy(item => item.Description).ToList();

        List<test> sortbyOwner = listOrder.OrderBy(item => item.Owner).ToList();

    }
}