如何使用自定义属性对类的属性进行排序

9

我有一个应用于类属性的自定义属性,用于将该类的属性导出到平面文件。

其中属性之一是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升序排序属性。


只是一个想法,也许更容易的方法是进行简单的XML序列化,然后编写一个库将简单的平面XML转换为平面文件。这样可以重复使用,并且可以跳过所有这些自定义属性设置工作和反射。 - asawyer
4个回答

29
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[]数组。

1
你可以使用以下两种选项之一。
第一种选项:将匿名函数传递给 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
你应该能够在每个 PropertyInfo 上使用 GetCustomAttributes() 方法来过滤具有正确属性的属性,然后对剩余项进行排序。

0
        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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接