Как отсортировать свойства в классе с помощью пользовательских атрибутов свойств - PullRequest
8 голосов
/ 29 июля 2011

У меня есть собственный атрибут, который я применяю к свойствам класса. Этот атрибут используется для экспорта свойств класса в плоский файл.

Одним из свойств атрибута является FieldOrder. Мне нужно убедиться, что порядок, в котором я экспортирую свойства класса, правильный. Кроме того, не все свойства класса будут иметь пользовательский атрибут.

Я нашел эту статью: Как отсортировать общий список на основе настраиваемого атрибута? В этом решении предполагается, что все свойства имеют настраиваемый атрибут, что не в моем случае. Я также надеялся на более элегантное решение.

Ваша помощь очень ценится!

public interface IFileExport{}

public class ExportAttribute: Attribute
{
    public int FieldOrder { get; set; }
    public int FieldLength { get; set; }
    public ExportAttribute() { }
}

public class ExportClass: IFileExport
{
    [ExportAttribute( FieldOrder = 2, FieldLength = 25 )]
    public string LastName { get; set; }

    [ExportAttribute( FieldOrder=1, FieldLength=25)]
    public string FirstName { get; set; }

    [ExportAttribute( FieldOrder = 3, FieldLength = 3 )]
    public int Age { get; set; }

    public ExportClass() { }
}

public class TestClass
{
    public static List<PropertyInfo> GetPropertiesSortedByFieldOrder
                                                            (IFileExport fileExport)
    {
        //get all properties on the IFileExport object
        PropertyInfo[] allProperties = fileExport
                         .GetType()
                         .GetProperties( BindingFlags.Instance | BindingFlags.Public );
        // now I need to figure out which properties have the ExportAttribute 
        //and sort them by the ExportAttribute.FieldOrder
    }
}

ОБНОВЛЕНИЕ: я упорядочиваю свойства по ExportAttribute.FieldOrder Ascending

Ответы [ 4 ]

25 голосов
/ 29 июля 2011
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder( IFileExport    fileExport )
{
    PropertyInfo[] allProperties = GetType()
        .GetProperties(BindingFlags.Instance | BindingFlags.Public)
        .Select(x => new 
        { 
            Property = x, 
            Attribute = (ExportAttribute)Attribute.GetCustomAttribute(x, typeof(ExportAttribute), true) 
        })
        .OrderBy(x => x.Attribute != null ? x.Attribute.FieldOrder : -1)
        .Select(x => x.Property)
        .ToArray();
}

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

  1. Получить свойства
  2. Бросить их в анонимный тип, чтобы иметь легкий доступ как к свойству, так и к атрибуту.
  3. Заказ по FieldOrder, используя -1 для свойств без атрибута.(не уверен, что вы хотели здесь)
  4. Преобразуйте последовательность обратно в последовательность PropertyInfo
  5. Преобразуйте ее в массив PropertyInfo[].
0 голосов
/ 05 января 2017

Вы можете использовать любой из следующих параметров.

Первый вариант: передать анонимную функцию в OrderBy

return allProperties.OrderBy(m => m.GetCustomAttribute<ExportAttribute>() == null ? -1 : 
                                      m.GetCustomAttribute<ExportAttribute>().FieldOrder).ToList();

Второй вариант: создать функцию выбора ключа и передать ее в OrderBy

return allProperties.OrderBy(KeySelector).ToList();

Функция ключевого селектора определена как здесь:

    public static int KeySelector(PropertyInfo info)
    {
        ExportAttribute attr = info.GetCustomAttribute<ExportAttribute>();
        return attr == null ? -1 : attr.FieldOrder;
    }

Если свойство не имеет ExportAttribute, селектор вернет -1. Вы можете выбрать любое другое значение по умолчанию.

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

0 голосов
/ 29 июля 2011
        static void Main(string[] args)
    {
        //get all properties on the IFileExport object
        PropertyInfo[] allProperties = fileExport.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
        Array.Sort(allProperties, ArrayAttributeComparison);


    }

    private static int ArrayAttributeComparison(PropertyInfo x, PropertyInfo y)
    {
        //Do null checks here
        ExportAttribute xExportAttribute = GetExportAtribute(x);
        ExportAttribute yExportAttribute = GetExportAtribute(x);
        //Do null checks here
        return xExportAttribute.FieldOrder - yExportAttribute.FieldOrder;
    }

    private static ExportAttribute GetExportAtribute(PropertyInfo propertyInfo)
    {
        object[] attributes = propertyInfo.GetCustomAttributes(true);
        foreach (var t in attributes)
        {
            if (t is ExportAttribute)
            {
                return (ExportAttribute)t;
            }
        }
        return null;
    }
0 голосов
/ 29 июля 2011

Вы должны иметь возможность использовать метод GetCustomAttributes () в каждом PropertyInfo, чтобы фильтровать свойства с правильными атрибутами и затем сортировать оставшиеся элементы.

...