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

时间:2014-03-10 17:09:31

标签: c# linq c#-4.0 reflection

请参阅此代码

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

}

我需要通过order的orderAttribute按顺序获取类的所有属性。我已尝试使用此代码执行

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

但是会导致错误

  

对象引用不设置对象的实例

我认为这个问题是因为某些属性在“DisplayAttribute”中没有“Order”属性。

如何处理这种情况?我需要订购所有属性,即使某些属性没有order属性的值。

4 个答案:

答案 0 :(得分:7)

()运算符上缺少括号FirstOrDefault。此外,您应该在返回 default 值时处理大小写。我建议在获得第一个或默认值之前选择Order值。对于没有0的所有属性,这将返回DisplayAttribute

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

如果您希望没有DisplayAttribute的属性为last,则可以提供Int32.MaxValue作为要返回的默认值:

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

答案 1 :(得分:3)

试试这个:

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;

答案 2 :(得分:2)

这是一个更完整的答案,可让您更好地控制PropertyInfo个实例的排序,而不需要DisplayAttribute属性:

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());

答案 3 :(得分:0)

我喜欢Comparer的方法。但是,当我尝试它时,我的迭代器首先进入死循环。后来,它开始抛出异常。另外,我对第一个属性不包含“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”描述符的任何属性。如果其中至少有一个具有该描述符,则进行排序。