简体   繁体   English

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

[英]Get properties of class by order using reflection

Please refer to this code 请参考此代码

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

}

I need to get all properties of class through order by orderAttribute of Display. 我需要通过order的orderAttribute按顺序获取类的所有属性。 I have tried with this code to do 我试过这个代码

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

but it causes an error 但它会导致错误

object reference not to set an instance of object 对象引用不设置对象的实例

I assumed this issue because of some property not having "Order" property in "DisplayAttribute" . 我假设这个问题是因为某些属性在“DisplayAttribute”中没有“Order”属性。

How to handle this kind of situation? 如何处理这种情况? I need to order all the properties even though some property not having the value of order property. 我需要订购所有属性,即使某些属性没有order属性的值。

You are missing brackets () on FirstOrDefault operator. 您在FirstOrDefault运算符上缺少方括号() Also you should deal with case when default value is returned. 此外,您应该在返回默认值时处理大小写。 I suggest to select Order value before getting first or default value. 我建议在获得第一个或默认值之前选择Order值。 That will return 0 for all properties which don't have DisplayAttribute : 对于没有DisplayAttribute所有属性,它将返回0

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

If you want properties without DisplayAttribute to be last, you can provide Int32.MaxValue as default value to be returned: 如果您希望没有DisplayAttribute的属性为last,则可以提供Int32.MaxValue作为要返回的默认值:

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

Try this: 尝试这个:

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;

Or: 要么:

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;

Here is a much more complete answer that allows you to better control the ordering of PropertyInfo instances without DisplayAttribute attributes: 这是一个更完整的答案,它允许您在没有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;
    }
}

Usage: 用法:

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

I like the approach with Comparer. 我喜欢Comparer的方法。 However, when I tried it, my iterator went into a dead loop at first. 但是,当我尝试它时,我的迭代器首先进入死循环。 Later, it started throwing exceptions. 后来,它开始抛出异常。 Also, I optimized it for the case when first property doesn't contain "Order" descriptor to avoid even checking for a second one. 另外,我对第一个属性不包含“Order”描述符的情况进行了优化,以避免检查第二个属性。 I also moved all comments into the class description: 我还将所有评论都移到了课程描述中:

    /// <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);
        }
    }

Unfortunately, classes that have properties without the "Order" descriptor lose their "natural" order. 不幸的是,具有没有“Order”描述符的属性的类会失去“自然”顺序。 Therefore, I ended up checking for any properties that have the "Order" descriptor first. 因此,我最终检查了首先具有“Order”描述符的任何属性。 If at least one of them has that descriptor, then do the sorting. 如果其中至少有一个具有该描述符,则进行排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM