【问题标题】:Getting attributes of Enum's value获取枚举值的属性
【发布时间】:2010-12-20 10:33:15
【问题描述】:

我想知道是否可以获得enum 值的属性而不是enum 本身的属性?例如,假设我有以下enum

using System.ComponentModel; // for DescriptionAttribute

enum FunkyAttributesEnum
{
    [Description("Name With Spaces1")]
    NameWithoutSpaces1,    
    [Description("Name With Spaces2")]
    NameWithoutSpaces2
}

我想要的是给定枚举类型,生成 2 元组的枚举字符串值及其描述。

价值很简单:

Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
    Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);

但是我如何获取描述属性的值来填充Tuple.Desc?如果属性属于enum本身,我可以想到怎么做,但是我不知道如何从enum的值中获取它。

【问题讨论】:

标签: c# reflection enums .net-attributes


【解决方案1】:

这应该可以满足您的需求。

try
{
  var enumType = typeof(FunkyAttributesEnum);
  var memberInfos = 
  enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
  var enumValueMemberInfo = memberInfos.FirstOrDefault(m => 
  m.DeclaringType == enumType);
  var valueAttributes = 
  enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
  var description = ((DescriptionAttribute)valueAttributes[0]).Description;
}
catch
{
    return FunkyAttributesEnum.NameWithoutSpaces1.ToString()
}

【讨论】:

  • 可选择使用 type.GetFields(BindingFlags.Public | BindingFlags.Static) 一次获取所有 memInfos。
  • 我不得不去 typeof(FunkyAttributesEnum),但除此之外它运行良好。谢谢。
  • @AlexK 我没有看到 Enum 类有 NameWithoutSpaces1 属性。 FunkyAttributesEnum.NameWithoutSpaces1 来自哪里?
  • @Don,这是 OP 问题中的枚举成员名称。
【解决方案2】:

这段代码应该在任何枚举上为您提供一个不错的小扩展方法,让您检索通用属性。我相信它与上面的 lambda 函数不同,因为它使用起来更简单,而且稍微有点——你只需要传入泛型类型。

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example><![CDATA[string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;]]></example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (attributes.Length > 0) ? (T)attributes[0] : null;
    }
}

【讨论】:

  • 用法将是:string desc = myEnumVariable.GetAttributeOfType().Description;
  • 如果不存在属性,这不会抛出IndexOutOfRangeException吗?
  • 对 memInfo 更好地使用 type.GetMember(Enum.GetName(type, enumVal)) 因为 enumVal.ToString() 对于不同的语言环境可能不可靠。
  • 调用GetCustomAttributes() 然后获取第一个元素而不是调用GetCustomAttribute() 有什么意义?
  • @tigrou 这个扩展是最近添加到 .NET 框架中的;解决方案(从 2009 年开始)可能需要更新。
【解决方案3】:

这是一个使用 lambda 进行选择的通用实现

public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
    where T : Attribute
{
    T attribute =
      enumeration
        .GetType()
        .GetMember(enumeration.ToString())
        .Where(member => member.MemberType == MemberTypes.Field)
        .FirstOrDefault()
        .GetCustomAttributes(typeof(T), false)
        .Cast<T>()
        .SingleOrDefault();

    if (attribute == null)
        return default(Expected);

    return expression(attribute);
}

这样称呼它:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);

【讨论】:

  • 这很棒。如果给定的枚举值是一个组合(FlagsAttribute 允许),我们只需要小心。在这种情况下,enumeration.GetType().GetMember(enumeration.ToString())[0] 将失败。
  • 你可以写的最短:value.GetType().GetField(value.ToString()).GetCustomAttributes(false).OfType&lt;T&gt;‌​().SingleOrDefault(),但必须承认你的明确方式更好。
  • 我还添加了 public static String GetDescription(this Enum enumeration) { return enumeration.GetAttributeValue(x => x.Description); } 这样它只是 targetLevel.GetDescription();
【解决方案4】:

我在这里合并了几个答案,以创建一个更具扩展性的解决方案。我提供它是为了以防将来对其他人有帮助。原帖here

using System;
using System.ComponentModel;

public static class EnumExtensions {

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0 
          ? (T)attributes[0]
          : null;
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value) {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

}

此解决方案在 Enum 上创建了一对扩展方法。第一个允许您使用反射来检索与您的值关联的任何属性。第二个专门调用检索DescriptionAttribute 并返回它的Description 值。

例如,考虑使用来自System.ComponentModelDescriptionAttribute 属性

using System.ComponentModel;

public enum Days {
    [Description("Sunday")]
    Sun,
    [Description("Monday")]
    Mon,
    [Description("Tuesday")]
    Tue,
    [Description("Wednesday")]
    Wed,
    [Description("Thursday")]
    Thu,
    [Description("Friday")]
    Fri,
    [Description("Saturday")]
    Sat
}

要使用上述扩展方法,您现在只需调用以下代码:

Console.WriteLine(Days.Mon.ToName());

var day = Days.Mon;
Console.WriteLine(day.ToName());

【讨论】:

  • 在最后一行,你的意思是“attribute.Description”?返回属性 == 空? value.ToString() : attribute.Description;
  • 我喜欢这个解决方案,但它有一个错误。 GetAttribute 方法假定枚举值具有 Description 属性,因此当属性长度为 0 时会引发异常。替换“return (T)attributes[0];”与“返回(attributes.Length > 0 ? (T)attributes[0] : null);”
  • @SimonGymer 感谢您的建议 - 我已相应更新。 :)
  • 最佳和最简单的答案。
【解决方案5】:

除了AdamCrawford response,我还进一步创建了一个更专业的扩展方法,用于获取描述。

public static string GetAttributeDescription(this Enum enumValue)
{
    var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
    return attribute == null ? String.Empty : attribute.Description;
} 

因此,要获取描述,您可以使用原始扩展方法作为

string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description

或者你可以在这里简单地调用扩展方法:

string desc = myEnumVariable.GetAttributeDescription();

这有望使您的代码更具可读性。

【讨论】:

    【解决方案6】:

    流利的一个班轮...

    这里我使用的是DisplayAttribute,它同时包含NameDescription 属性。

    public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
    {
        return enumType.GetMember(enumValue.ToString())
                       .First()
                       .GetCustomAttribute<DisplayAttribute>();
    }
    

    示例

    public enum ModesOfTransport
    {
        [Display(Name = "Driving",    Description = "Driving a car")]        Land,
        [Display(Name = "Flying",     Description = "Flying on a plane")]    Air,
        [Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
    }
    
    void Main()
    {
        ModesOfTransport TransportMode = ModesOfTransport.Sea;
        DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
        Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
    }
    

    输出

    Name: Sea cruise 
    Description: Cruising on a dinghy
    

    【讨论】:

    • 我也用这个,它是所有答案中最干净的! +1
    • 这似乎很有用!谢谢
    • 您可以使用 enumValue.GetType() 来消除 enumType 参数。
    【解决方案7】:

    这是从 Display 属性获取信息的代码。它使用通用方法来检索属性。如果未找到该属性,则将枚举值转换为字符串,将 pascal/camel 大小写转换为标题大小写(代码获得 here

    public static class EnumHelper
    {
        // Get the Name value of the Display attribute if the   
        // enum has one, otherwise use the value converted to title case.  
        public static string GetDisplayName<TEnum>(this TEnum value)
            where TEnum : struct, IConvertible
        {
            var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
            return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
        }
    
        // Get the ShortName value of the Display attribute if the   
        // enum has one, otherwise use the value converted to title case.  
        public static string GetDisplayShortName<TEnum>(this TEnum value)
            where TEnum : struct, IConvertible
        {
            var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
            return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
        }
    
        /// <summary>
        /// Gets an attribute on an enum field value
        /// </summary>
        /// <typeparam name="TEnum">The enum type</typeparam>
        /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
        /// <param name="value">The enum value</param>
        /// <returns>The attribute of type T that exists on the enum value</returns>
        private static T GetAttributeOfType<TEnum, T>(this TEnum value)
            where TEnum : struct, IConvertible
            where T : Attribute
        {
    
            return value.GetType()
                        .GetMember(value.ToString())
                        .First()
                        .GetCustomAttributes(false)
                        .OfType<T>()
                        .LastOrDefault();
        }
    }
    

    这是字符串转换为标题大小写的扩展方法:

        /// <summary>
        /// Converts camel case or pascal case to separate words with title case
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToSpacedTitleCase(this string s)
        {
            //https://stackoverflow.com/a/155486/150342
            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            TextInfo textInfo = cultureInfo.TextInfo;
            return textInfo
               .ToTitleCase(Regex.Replace(s, 
                            "([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
        }
    

    【讨论】:

      【解决方案8】:

      我实现了这个扩展方法来从枚举值中获取描述。它适用于所有类型的枚举。

      public static class EnumExtension
      {
          public static string ToDescription(this System.Enum value)
          {
              FieldInfo fi = value.GetType().GetField(value.ToString());
              var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
              return attributes.Length > 0 ? attributes[0].Description : value.ToString();
          }
      }
      

      【讨论】:

      • 相同解决方案的通用版本已经发布。 imo,更好。
      【解决方案9】:

      从枚举中获取字典。

      public static IDictionary<string, int> ToDictionary(this Type enumType)
      {
          return Enum.GetValues(enumType)
          .Cast<object>()
          .ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k); 
      }
      

      现在这样称呼...

      var dic = typeof(ActivityType).ToDictionary();
      

      EnumDecription Ext 方法

      public static string ToEnumDescription(this Enum en) //ext method
      {
          Type type = en.GetType();
          MemberInfo[] memInfo = type.GetMember(en.ToString());
          if (memInfo != null && memInfo.Length > 0)
          {
              object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
              if (attrs != null && attrs.Length > 0)
                  return ((DescriptionAttribute)attrs[0]).Description;
          }
          return en.ToString();
      }
      
      public enum ActivityType
      {
          [Description("Drip Plan Email")]
          DripPlanEmail = 1,
          [Description("Modification")]
          Modification = 2,
          [Description("View")]
          View = 3,
          [Description("E-Alert Sent")]
          EAlertSent = 4,
          [Description("E-Alert View")]
          EAlertView = 5
      }
      

      【讨论】:

        【解决方案10】:

        我的这个答案是从枚举属性中设置一个组合框,这很棒。

        然后我需要对相反的代码进行编码,以便我可以从框中获取选择并以正确的类型返回枚举。

        我还修改了代码以处理缺少属性的情况

        为了下一个人的利益,这里是我的最终解决方案

        public static class Program
        {
           static void Main(string[] args)
            {
               // display the description attribute from the enum
               foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour)))
               {
                    Console.WriteLine(EnumExtensions.ToName(type));
               }
        
               // Get the array from the description
               string xStr = "Yellow";
               Colour thisColour = EnumExtensions.FromName<Colour>(xStr);
        
               Console.ReadLine();
            }
        
           public enum Colour
           {
               [Description("Colour Red")]
               Red = 0,
        
               [Description("Colour Green")]
               Green = 1,
        
               [Description("Colour Blue")]
               Blue = 2,
        
               Yellow = 3
           }
        }
        
        public static class EnumExtensions
        {
        
            // This extension method is broken out so you can use a similar pattern with 
            // other MetaData elements in the future. This is your base method for each.
            public static T GetAttribute<T>(this Enum value) where T : Attribute
            {
                var type = value.GetType();
                var memberInfo = type.GetMember(value.ToString());
                var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        
                // check if no attributes have been specified.
                if (((Array)attributes).Length > 0)
                {
                    return (T)attributes[0];
                }
                else
                {
                    return null;
                }
            }
        
            // This method creates a specific call to the above method, requesting the
            // Description MetaData attribute.
            public static string ToName(this Enum value)
            {
                var attribute = value.GetAttribute<DescriptionAttribute>();
                return attribute == null ? value.ToString() : attribute.Description;
            }
        
            /// <summary>
            /// Find the enum from the description attribute.
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="desc"></param>
            /// <returns></returns>
            public static T FromName<T>(this string desc) where T : struct
            {
                string attr;
                Boolean found = false;
                T result = (T)Enum.GetValues(typeof(T)).GetValue(0);
        
                foreach (object enumVal in Enum.GetValues(typeof(T)))
                {
                    attr = ((Enum)enumVal).ToName();
        
                    if (attr == desc)
                    {
                        result = (T)enumVal;
                        found = true;
                        break;
                    }
                }
        
                if (!found)
                {
                    throw new Exception();
                }
        
                return result;
            }
        }
        

        }

        【讨论】:

        • 伙计,我见过这么多愚蠢且无法解释的解决方案,而您的解决方案却杀死了它。非常感谢
        【解决方案11】:

        这是 AdamCrawford 的答案的 .NET Core 版本,使用 System.Reflection.TypeExtensions

        public static class EnumHelper
        {
            /// <summary>
            /// Gets an attribute on an enum field value
            /// </summary>
            /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
            /// <param name="enumVal">The enum value</param>
            /// <returns>The attribute of type T that exists on the enum value</returns>
            /// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
            public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
            {
                var type = enumVal.GetType();
                var memInfo = type.GetMember(enumVal.ToString());
                IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
                return (T)attributes?.ToArray()[0];
            }
        }
        

        【讨论】:

        • 我不相信 .NET Core(或者更确切地说,现在是 Standard)有 GetMember,所以我不确定这将如何工作。
        • 它在 System.Reflection.TypeExtensions 中,我已经修改了我的答案以列出这个。
        • 明白了,谢谢。我认为可能会有一些扩展在起作用。
        【解决方案12】:

        为 Net Framework 和 NetCore 添加我的解决方案。

        我将它用于我的 Net Framework 实现:

        public static class EnumerationExtension
        {
            public static string Description( this Enum value )
            {
                // get attributes  
                var field = value.GetType().GetField( value.ToString() );
                var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );
        
                // return description
                return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
            }
        }
        

        这不适用于 NetCore,因此我对其进行了修改:

        public static class EnumerationExtension
        {
            public static string Description( this Enum value )
            {
                // get attributes  
                var field = value.GetType().GetField( value.ToString() );
                var attributes = field.GetCustomAttributes( false );
        
                // Description is in a hidden Attribute class called DisplayAttribute
                // Not to be confused with DisplayNameAttribute
                dynamic displayAttribute = null;
        
                if (attributes.Any())
                {
                    displayAttribute = attributes.ElementAt( 0 );
                }
        
                // return description
                return displayAttribute?.Description ?? "Description Not Found";
            }
        }
        

        枚举示例:

        public enum ExportTypes
        {
            [Display( Name = "csv", Description = "text/csv" )]
            CSV = 0
        }
        

        添加的任一静态示例用法:

        var myDescription = myEnum.Description();
        

        【讨论】:

          【解决方案13】:

          Bryan RoweAdamCrawford 感谢您的回答!

          但是如果有人需要获取描述的方法(不是扩展名),你可以使用它:

          string GetEnumDiscription(Enum EnumValue)
                  {
                      var type = EnumValue.GetType();
                      var memInfo = type.GetMember(EnumValue.ToString());
                      var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
                      return (attributes.Length > 0) ? ((DescriptionAttribute)attributes[0]).Description : null;
                  }
          

          【讨论】:

            【解决方案14】:

            利用一些较新的 C# 语言功能,您可以减少行数:

            public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumVal) where TAttribute : Attribute
            {
                var memberInfo = enumVal.GetType().GetMember(enumVal.ToString());
                return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType<TAttribute>().FirstOrDefault();
            }
            
            public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute<DescriptionAttribute>()?.Description ?? enumValue.ToString();
            

            【讨论】:

              【解决方案15】:

              如果您的 enum 包含像 Equals 这样的值,您可能会在此处的许多答案中使用一些扩展来遇到一些错误。这是因为通常假定typeof(YourEnum).GetMember(YourEnum.Value) 只会返回一个值,即enumMemberInfo。这是一个稍微安全一点的版本Adam Crawford's answer

              public static class AttributeExtensions
              {
                  #region Methods
              
                  public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
                  {
                      var type = enumValue.GetType();
                      var memberInfo = type.GetMember(enumValue.ToString());
                      var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
                      var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
                      return attribute is T ? (T)attribute : null;
                  }
              
                  #endregion
              }
              

              【讨论】:

                【解决方案16】:

                性能很重要

                如果你想获得更好的性能,这就是你要走的路:

                public static class AdvancedEnumExtensions
                {
                    /// <summary>
                    /// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
                    /// </summary>
                    public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
                    {
                        return GetField(value)?.GetCustomAttribute<T>(inherit: false);
                    }
                
                    /// <summary>
                    /// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
                    /// </summary>
                    public static FieldInfo GetField(this Enum value)
                    {
                        ulong u64 = ToUInt64(value);
                        return value
                            .GetType()
                            .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
                            .Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
                            .FirstOrDefault();
                    }
                
                    /// <summary>
                    /// Checks if an enum constant is defined for this enum value
                    /// </summary>
                    public static bool IsDefined(this Enum value)
                    {
                        return GetField(value) != null;
                    }
                
                    /// <summary>
                    /// Converts the enum value to UInt64
                    /// </summary>
                    public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);
                
                    private static ulong ToUInt64(object value)
                    {
                        switch (Convert.GetTypeCode(value))
                        {
                            case TypeCode.SByte:
                            case TypeCode.Int16:
                            case TypeCode.Int32:
                            case TypeCode.Int64:
                                return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));
                
                            case TypeCode.Byte:
                            case TypeCode.UInt16:
                            case TypeCode.UInt32:
                            case TypeCode.UInt64:
                            case TypeCode.Char:
                            case TypeCode.Boolean:
                                return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
                
                            default: throw new InvalidOperationException("UnknownEnumType");
                        }
                    }
                }
                

                为什么这有更好的性能?

                因为内置方法都使用与此非常相似的代码,除了 它们还运行一堆我们不关心的其他代码。 C# 的 Enum 代码总体上是相当糟糕的。

                上面的代码已经过 Linq 化和精简,所以它只包含我们关心的位。

                为什么内置代码很慢?

                首先关于 Enum.ToString() -vs- Enum.GetName(..)

                始终使用后者。 (或者更好的是,这将在下面变得清楚。)

                ToString() 在内部使用后者,但同样,它也做了很多其他我们不想要的东西,例如尝试组合标志、打印数字等。我们只对枚举中定义的常量感兴趣。

                Enum.GetName 依次获取所有字段,为所有名称创建字符串数组,在其所有 RawConstantValues 上使用上面的 ToUInt64 创建所有值的 UInt64 数组,根据 UInt64 值对两个数组进行排序,最后得到通过在 UInt64 数组中执行 BinarySearch 来查找我们想要的值的索引,从名称数组中获取名称。

                ...然后我们将字段和已排序的数组丢弃,然后使用该名称再次找到该字段。

                一个字:“啊!”

                【讨论】:

                  【解决方案17】:

                  对于一些程序员的幽默,一个班轮作为一个笑话:

                  public static string GetDescription(this Enum value) => value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : string.Empty;
                  

                  以更易读的形式:

                  using System;
                  using System.ComponentModel;
                  using System.Linq;
                  using System.Reflection;
                  
                  public static class EnumExtensions
                  {
                      // get description from enum:
                  
                      public static string GetDescription(this Enum value)
                      {
                          return value.GetType().
                              GetMember(value.ToString()).
                              First().
                              GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute
                              ? attribute.Description
                              : throw new Exception($"Enum member '{value.GetType()}.{value}' doesn't have a [DescriptionAttribute]!");
                      }
                  
                      // get enum from description:
                  
                      public static T GetEnum<T>(this string description) where T : Enum
                      {
                          foreach (FieldInfo fieldInfo in typeof(T).GetFields())
                          {
                              if (fieldInfo.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute && attribute.Description == description)
                                  return (T)fieldInfo.GetRawConstantValue();
                          }
                  
                          throw new Exception($"Enum '{typeof(T)}' doesn't have a member with a [DescriptionAttribute('{description}')]!");
                      }
                  }
                  

                  【讨论】:

                    【解决方案18】:
                        public enum DataFilters
                        {
                            [Display(Name= "Equals")]
                            Equals = 1,// Display Name and Enum Name are same 
                            [Display(Name= "Does Not Equal")]
                            DoesNotEqual = 2, // Display Name and Enum Name are different             
                        }
                    

                    现在在这种情况下会产生错误 1 ​​"Equals"

                    public static string GetDisplayName(this Enum enumValue)
                        {
                            var enumMember = enumValue.GetType().GetMember(enumValue.ToString()).First();
                            return enumMember.GetCustomAttribute<DisplayAttribute>() != null ? enumMember.GetCustomAttribute<DisplayAttribute>().Name : enumMember.Name;
                        }
                    

                    所以如果它是相同的返回枚举名称而不是显示名称,因为 enumMember.GetCustomAttribute() 如果显示名称和枚举名称相同,则为空.....

                    【讨论】:

                    • 此解决方案会两次获取属性,这会导致不必要的开销。考虑一次获取它,如果它不为 null,则返回它的 Name 属性。例如var attr = enumMember.GetCustomAttribute&lt;DisplayAttribute&gt;(); return attr != null ? attr.Name : enumMember.Name;
                    【解决方案19】:

                    型号

                    我们填充价值观的模型

                    public class MemberTypeModel : IDto
                    {
                        public string MemberAttributeName { get; set; }
                        public string MemberName { get; set; }
                        public int MemberValue { get; set; }
                    }
                    

                    枚举

                    我们的目标是枚举

                    public enum MemberType
                    {
                        [FieldText("Yönetim Kurul Üyesi")]
                        BoardManager = 0,
                    
                        [FieldText("Temsilci")]
                        Representative = 1,
                    
                        [FieldText("Üye")]
                        Member = 2
                    }
                    

                    辅助方法

                    我们将用来获取自定义属性对象的辅助方法

                    public T GetMemberCustomText<T>(MemberType memberType) where T : Attribute
                    {
                        var enumType = memberType.GetType();
                        var name = Enum.GetName(enumType, memberType);
                        return enumType.GetField(name).GetCustomAttributes(false).OfType<T>().SingleOrDefault();
                    }
                    

                    获取方法

                    首先我们提取枚举值并将它们转换为枚举类型。然后,使用我们知道的 Linq 选择查询;

                    • MemberAttributeName 字段和辅助方法,
                    • 使用 Enum.GetName 方法的成员名称字段,
                    • 还将 MemberValue 字段转换为 int 类型, 我们将其填写并变成一个列表。

                    public List<MemberTypeModel> GetMemberTypes()
                    {
                        var memberTypes = Enum.GetValues(typeof(MemberType))
                            .Cast<MemberType>()
                            .Select(et => new MemberTypeModel
                            {
                                MemberAttributeName = GetMemberCustomText<FieldText>(et).Text,
                                MemberName = Enum.GetName(et.GetType(), et),
                                MemberValue = (int)et
                            }).ToList();
                        return memberTypes;
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      或者,您可以执行以下操作:

                      Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
                          {
                            { FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
                            { FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
                          };
                      

                      并获得以下描述:

                      string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
                      

                      在我看来,这是一种更有效的方式来完成你想要完成的事情,因为不需要反思..

                      【讨论】:

                      • 当然,但反思并没有人们想象的那么糟糕。
                      • 并不是说它不好——我一直在使用它。但是,它经常被不必要地使用。 :)
                      • 这个解决方案将描述从枚举本身移开,造成至少两个大问题。首先,如果有人添加了一个新的 enum constant ,他们需要知道去这个其他地方也可以在那里添加一个条目。属性是维护者需要做什么的明确标志。我的第二个问题是它只是更多的代码。属性紧凑。
                      • @scott 但它确实允许您指定自己的顺序,并排除您不想显示的值,这几乎总是我真正想要的
                      【解决方案21】:

                      此扩展方法将使用其 XmlEnumAttribute 获取枚举值的字符串表示形式。如果不存在 XmlEnumAttribute,则回退到 enum.ToString()。

                      public static string ToStringUsingXmlEnumAttribute<T>(this T enumValue)
                          where T: struct, IConvertible
                      {
                          if (!typeof(T).IsEnum)
                          {
                              throw new ArgumentException("T must be an enumerated type");
                          }
                      
                          string name;
                      
                          var type = typeof(T);
                      
                          var memInfo = type.GetMember(enumValue.ToString());
                      
                          if (memInfo.Length == 1)
                          {
                              var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);
                      
                              if (attributes.Length == 1)
                              {
                                  name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name;
                              }
                              else
                              {
                                  name = enumValue.ToString();
                              }
                          }
                          else
                          {
                              name = enumValue.ToString();
                          }
                      
                          return name;
                      }
                      

                      【讨论】:

                        【解决方案22】:

                        如果有帮助,我将与您分享我的解决方案: 自定义属性定义:

                            [AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
                        public class EnumDisplayName : Attribute
                        {
                            public string Name { get; private set; }
                            public EnumDisplayName(string name)
                            {
                                Name = name;
                            }
                        }
                        

                        现在因为我需要它在 HtmlHelper 扩展的 HtmlHelper 定义中:

                        public static class EnumHelper
                        {
                            public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
                            {
                                //Get every fields from enum
                                var fields = priceType.GetType().GetFields();
                                //Foreach field skipping 1`st fieldw which keeps currently sellected value
                                for (int i = 0; i < fields.Length;i++ )
                                {
                                    //find field with same int value
                                    if ((int)fields[i].GetValue(priceType) == (int)priceType)
                                    {
                                        //get attributes of found field
                                        var attributes = fields[i].GetCustomAttributes(false);
                                        if (attributes.Length > 0)
                                        {
                                            //return name of found attribute
                                            var retAttr = (EnumDisplayName)attributes[0];
                                            return retAttr.Name;
                                        }
                                    }
                                }
                                //throw Error if not found
                                throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
                            }
                        }
                        

                        希望对你有帮助

                        【讨论】:

                          【解决方案23】:

                          如果你想要完整的名字列表,你可以这样做

                          typeof (PharmacyConfigurationKeys).GetFields()
                                  .Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
                                  .Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
                          

                          【讨论】:

                            【解决方案24】:

                            或者,您可以执行以下操作:

                            List<SelectListItem> selectListItems = new List<SelectListItem>();
                            
                                foreach (var item in typeof(PaymentTerm).GetEnumValues())
                                {
                                    var type = item.GetType();
                                    var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
                                    selectListItems.Add(new SelectListItem(name, type.Name));
                            
                                }
                            

                            【讨论】:

                              【解决方案25】:

                              这就是我在不使用 .NET core 3.1 的自定义帮助程序或扩展的情况下解决它的方法。

                              public enum YourEnum
                              {
                                  [Display(Name = "Suryoye means Arameans")]
                                  SURYOYE = 0,
                                  [Display(Name = "Oromoye means Syriacs")]
                                  OROMOYE = 1,
                              }
                              

                              剃须刀

                              @using Enumerations
                              
                              foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
                              {
                                  <h1>@name.Text</h1>
                              }
                              

                              【讨论】:

                              • 考虑用更多的方法来回答这个问题,而不是你如何解决“它” - 首先承认问题并解释你认为它如何解决“它”。请记住,从现在开始的几年内,您的答案可能会断章取义,然后几乎没有用。添加更多内容,添加一些上下文可以提升您的答案及其可能的历史/档案相关性
                              猜你喜欢
                              • 2020-12-31
                              • 2011-02-16
                              • 1970-01-01
                              • 2013-01-18
                              • 2013-08-14
                              • 1970-01-01
                              相关资源
                              最近更新 更多