使用反射按顺序获取类的属性

本文关键字:属性 获取 顺序 反射 | 更新日期: 2023-09-27 17:49:25

请参考此代码

public class A : B
{
     [Display(Name = "Initial Score Code", Order =3)]
     public Code { get; set; }
     [Display(Name = "Initial Score Code", Order =2)]
     public Name{ get; set; }
............
}

我需要通过orderAttribute of Display获得类的所有属性。我已经尝试用这个代码做

 var prop = typeof(A)
            .GetProperties()
            .OrderBy(p => ((DisplayAttribute)p.GetCustomAttributes(typeof(DisplayAttribute),  true).FirstOrDefault).Order);

但是会导致错误

对象引用不设置对象

的实例

我认为这个问题是因为一些属性在"DisplayAttribute"中没有"Order"属性。

如何处理这种情况?我需要对所有属性进行排序即使有些属性没有order属性的值

使用反射按顺序获取类的属性

您在FirstOrDefault操作符上缺少括号()。此外,您还应该处理返回默认值的情况。我建议选择先获取Order值或默认值。这将为所有没有DisplayAttribute的属性返回0:

var prop = typeof(A)
    .GetProperties()
    .OrderBy(p => p.GetCustomAttributes(typeof(DisplayAttribute), true)
                   .Cast<DisplayAttribute>()
                   .Select(a => a.Order)
                   .FirstOrDefault());

如果你想把没有DisplayAttribute的属性放在最后,你可以提供Int32.MaxValue作为默认值返回:

                   .Select(a => a.Order)
                   .DefaultIfEmpty(Int32.MaxValue)
                   .First()

试试这个:

var props = from p in typeof(A).GetProperties()
    let orderAttribute = (DisplayAttribute)(p.GetCustomAttributes(typeof(DisplayAttribute), true))
        .FirstOrDefault()
    where orderAttribute != null
    orderby orderAttribute.Order
    select p;

或:

var props = from p in typeof(A).GetProperties()
    let orderAttribute = (DisplayAttribute)(p.GetCustomAttributes(typeof(DisplayAttribute), true))
        .FirstOrDefault()
    orderby orderAttribute == null ? 0 : orderAttribute.Order
    select p;

这里有一个更完整的答案,允许您在没有DisplayAttribute属性的情况下更好地控制PropertyInfo实例的排序:

public class A
{
    [Display(Name = "Initial Score Code", Order = 3)]
    public int Code
    {
        get;
        set;
    }
    [Display(Name = "Initial Score Code", Order = 2)]
    public string Name
    {
        get;
        set;
    }
}
public class PropertyInfoComparer : IComparer<PropertyInfo>
{
    public int Compare(PropertyInfo x, PropertyInfo y)
    {
        var attribute1 = (DisplayAttribute)x.GetCustomAttributes(typeof(DisplayAttribute)).FirstOrDefault();
        var attribute2 = (DisplayAttribute)y.GetCustomAttributes(typeof(DisplayAttribute)).FirstOrDefault();
        // If the first property has no attribute, sort it first
        if (attribute1 == null)
        {
            return -1;
        }
        // If the second property has no attribute, sort it first
        if (attribute2 == null)
        {
            return 1;
        }
        // Compare the Order properties of both attributes
        return attribute1.Order.CompareTo(attribute2.Order);
    }
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DisplayAttribute : Attribute
{
    public string Name
    {
        get;
        set;
    }
    public int Order
    {
        get;
        set;
    }
}

用法:

// Get all the properties of Foo and order them using PropertyInfoComparer
typeof(Foo).GetProperties().OrderBy(arg => arg, new PropertyInfoComparer());

我喜欢比较器的方法。然而,当我尝试它时,我的迭代器一开始就进入了死循环。后来,它开始抛出异常。此外,我还针对第一个属性不包含"Order"描述符的情况对其进行了优化,以避免检查第二个属性。我还将所有注释移到了类描述中:

    /// <summary>
    /// If the first property has no attribute, sort it first
    /// If the second property has no attribute, sort it first
    /// Compare the Order properties of both attributes
    /// </summary>
    public class PropertyInfoComparer : IComparer<PropertyInfo>
    {
        public int Compare(PropertyInfo x, PropertyInfo y)
        {
            if (x == y) return 0;
            var attrX = (DisplayAttribute)x.GetCustomAttributes(typeof(DisplayAttribute)).FirstOrDefault();
            int? orderX = attrX?.GetOrder();
            if (orderX == null) return -1;
            var attrY = (DisplayAttribute)y.GetCustomAttributes(typeof(DisplayAttribute)).FirstOrDefault();
            int? orderY = attrY?.GetOrder();
            if (orderY == null) return 1;
            return ((int)orderX).CompareTo((int)orderY);
        }
    }

不幸的是,那些没有"Order"描述符的类失去了它们的"自然"顺序。因此,我首先检查具有"Order"描述符的任何属性。如果它们中至少有一个具有该描述符,则进行排序。