Enum属性第一次访问后改变顺序

本文关键字:改变 顺序 访问 属性 第一次 Enum | 更新日期: 2023-09-27 18:11:03

我们有以下enum:

public enum TrafficLight
    {
        [Description("../../images/dot-red.png")]
        [AwesomeIcon("<i class='fa fa-lg fa-circle v4-red'></i>")]
        Red = 0,
        [Description("../../images/dot-yellow.png")]
        [AwesomeIcon("<i class='fa fa-lg fa-circle v4-yellow'></i>")]
        Yellow = 1,
        [Description("../../images/dot-green.png")]
        [AwesomeIcon("<i class='fa fa-lg fa-circle v4-green'></i>")]
        Green = 2,
        [Description("../../images/dot-gold.png")]
        [AwesomeIcon("<i class='fa fa-lg fa-circle v4-gold'></i>")]
        Gold = 3,
        [Description("../../images/dot-grey.png")]
        [AwesomeIcon("<i class='fa fa-lg fa-circle v4-grey'></i>")]
        Grey = 99
    }

AwesomeIcon继承自DescriptionAttribute类:

 public class AwesomeIcon : DescriptionAttribute
    {
        public AwesomeIcon(string icon)
            : base(icon)
        {
        }
    }

问题是当枚举描述被访问不止一次时,属性的顺序发生了变化。例如,我们得到这样的描述:

 public static string GetEnumDescription(Enum value, int index = 0)
        {
            var fi = value.GetType().GetField(value.ToString());
            var attributes =
                fi.GetCustomAttributes(typeof (DescriptionAttribute), false) as DescriptionAttribute[];
            if(attributes == null)
            {
                return string.Empty;
            }
            if (attributes.Any() && index <= attributes.Length)
            {
                return attributes[index].Description;
            }   
            return value.ToString();
        }

第一次访问

GetEnumDescription(TrafficLight.Red);
//Returns "../../images/dot-red.png" as expected.
//Debug GetEnumDescription attributes variable
[0]Description
[1]AwesomeIcon

第二次访问

GetEnumDescription(TrafficLight.Yellow);
//Returns "<i class='fa fa-lg fa-circle v4-yellow'></i>" 
// which is the value of AwesomeIcon.
//Debug GetEnumDescription attributes variable
[0]AwesomeIcon
[1]Description

顺序之后的每个访问都是AwesomeIcon,然后是Description

问题是AwesomeIcon继承自Description并且它正在被拾取。如果数组中的顺序保持不变,就不会有问题,我可以通过索引引用它。

我以前没有经历过这种情况,有什么想法吗?

Enum属性第一次访问后改变顺序

您可以确保您有一个DescriptionAttribute(即使它是继承的),如:

var fi = value.GetType().GetField(value.ToString());
var attributes = fi.GetCustomAttributes(typeof (DescriptionAttribute), false);
var myDescriptionAttribute = 
      attributes.FirstOrDefault(x => x.GetType() == typeof(DescriptionAttribute)) as DescriptionAttribute;

忘掉索引。属性不能保证顺序,所以索引是相当无用的。

通过使用x => x.GetType() == typeof(DescriptionAttribute),您可以获得精确的类型匹配。

我做了一个演示两种可能的方法(使用泛型或只是找到DescriptionAttribute): https://dotnetfiddle.net/StUvqf

但基本上:

public static string GetEnumDescription(Enum value)
{
    var fi = value.GetType().GetField(value.ToString());
    var attributes = fi.GetCustomAttributes(typeof (DescriptionAttribute), false);
    var theDescriptionAttribute = attributes.FirstOrDefault(x => x.GetType() == typeof (DescriptionAttribute)) as DescriptionAttribute;
    if (theDescriptionAttribute == null)
    {
        return string.Empty;
    }
    return theDescriptionAttribute.Description;
}

或:

public static string GetEnumDescription<T>(Enum value)
    where T : DescriptionAttribute
{
    var fi = value.GetType().GetField(value.ToString());
    var attributes = fi.GetCustomAttributes(typeof (T), false);
    var theDescriptionAttribute = attributes.FirstOrDefault(x => x.GetType() == typeof (T)) as T;
    if (theDescriptionAttribute == null)
    {
        return string.Empty;
    }
    return theDescriptionAttribute.Description;
}

当然可能需要更多的null检查,但我将把它留给你

作为一个额外的提示,FieldInfo.GetCustomAttributes永远不会返回null(它可能返回一个空数组,但不是null),所以您可以删除null检查:-)

作为一种快速修复方法,您可以按名称对属性进行排序,这将帮助您每次都以相同的顺序获得它们。

var attributes =
         fi.GetCustomAttributes(typeof (DescriptionAttribute), false) as object[];
if(attributes.Any())
  {
   // Ascending order
   Array.Sort(attributes, (x, y) => 
    String.Compare(x.GetType().Name, y.GetType().Name)); 
  }

修复GetEnumDescription(Enum value, int index = 0):

if (attributes.Any() && index <= attributes.Length) 
应该

if (attributes.Any() && index < attributes.Length)