Как отсортировать список <T>по свойству объекта с необязательным атрибутом order - PullRequest
0 голосов
/ 18 сентября 2018

Допустим, у меня есть базовый класс и два производных класса.

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. Id
  2. Страна
  3. Имя
  4. Описание
  5. Сумма
  6. Владелец
  7. Дата добавления
  8. Другое

Так что произойдет, если те, у кого есть CustomAttr[(Order = n)], должны быть размещены в порядке их собственности, а для тех, у кого их нет, мы предполагаем, что они находятся в надлежащем порядке.Это также должно иметь аналогичное поведение, если я использую класс Bar.

В случае использования этого мне нужно иметь правильный порядок свойств класса в List<T>, чтобы иметь правильныйпорядок столбцов в файле Excel.

Я должен был добавить CustomAttr[(Order = n)] ко всем свойствам, чтобы отсортировать их, однако это утомительная вещь, которая требует от вас изменить порядоквсе свойства, если вы попытаетесь изменить один из порядков свойств.

Есть ли способ добиться этого?

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

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

Попробуйте выполнить следующее:

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 , instance / non-static и , объявленные для определенного класса, с которым я сейчас обращаюсь ).

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 порядками, в соответствии с вашими потребностями.

Но я полагаю, что это немного выходит за рамки моего ответа (который намереваетсяпокажет вам, как получить порядок объявления свойств от базового класса к любому конкретному классу).

0 голосов
/ 18 сентября 2018

Я создал общее решение, прочитав ваш атрибут и создав сравнитель, который будет сравнивать в порядке вашего атрибута.в конструкторе компаратора я читаю над отражением твои атрибуты.Сравнивая, я беру одно свойство за другим и, когда оно равно (нулю), я перехожу к следующему.Логика также работает с наследованием, поэтому даже в базовом классе вы можете иметь 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;
        }
    }
}
0 голосов
/ 18 сентября 2018

См. Этот пример для заказа с использованием 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();

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