ChatGPT解决这个技术问题 Extra ChatGPT

获取枚举值的属性

我想知道是否可以获得 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的值中获取它。

描述所需的命名空间是 System.ComponentModel
您也可以不使用 System.ComponentModel 而只使用您自己的属性类型; DescriptionAttribute 并没有什么特别之处。

C
Community

这应该做你需要的。

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 问题中的枚举成员名称。
C
Community

这段代码应该在任何枚举上为您提供一个不错的小扩展方法,让您检索通用属性。我相信它与上面的 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 吗?
更好地将 type.GetMember(Enum.GetName(type, enumVal)) 用于 memInfo,因为 enumVal.ToString() 对于不同的语言环境可能不可靠。
调用 GetCustomAttributes() 然后获取第一个元素而不是调用 GetCustomAttribute() 有什么意义?
@tigrou 这个扩展是最近添加到 .NET 框架中的;解决方案(从 2009 年开始)可能需要更新。
M
M Reza

这是使用 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<T>‌​().SingleOrDefault(),但必须承认您的明确方式更好。
我还添加了 public static String GetDescription(this Enum enumeration) { return enumeration.GetAttributeValue(x => x.Description); } 这样它只是 targetLevel.GetDescription();
T
Troy Alford

我在这里合并了几个答案,以创建一个更具可扩展性的解决方案。我提供它是为了以防将来对其他人有帮助。原始发布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.ComponentModel 中的 DescriptionAttribute 属性

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() : 属性描述;
我喜欢这个解决方案,但它有一个错误。 GetAttribute 方法假定枚举值具有 Description 属性,因此当属性长度为 0 时会引发异常。替换“return (T)attributes[0];”与“返回(属性。长度> 0?(T)属性[0]:空);”
@SimonGymer 感谢您的建议-我已相应更新。 :)
最好和最简单的答案。
C
Community

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

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


A
Aydin

流利的一班轮...

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

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 参数。
C
Community

这是从 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 "));
    }

N
Nick N.

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

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

相同解决方案的通用版本已经发布。海事组织,更好。
J
Jitendra Pancholi

从枚举中获取字典。

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
}

w
wonea

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

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

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

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

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

}


伙计,我见过这么多愚蠢且无法解释的解决方案,而您的解决方案却杀死了它。非常感谢<3
w
wonea

这是 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 中,我已经修改了我的答案以列出这个。
明白了,谢谢。我认为可能会有一些扩展在起作用。
H
HouseCat

添加我的 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();

A
AnorZaken

性能很重要

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

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-array 中执行 BinarySearch 来查找我们想要的值的索引来查找 name-array。

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

一个字:“啊!”


К
Константин Золин

Bryan Rowe 和 AdamCrawford 感谢您的回答!

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

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

w
wonea

利用一些较新的 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();

P
Prince Owen

如果您的 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
}

J
Jinjinov

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

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}')]!");
    }
}

M
Mohit Dhawan
    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 .....


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

模型

我们填充价值观的模型

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 方法的 MemberName 字段,

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

I
Ian P

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

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,但它确实允许您指定自己的顺序,并排除您不想显示的值,这几乎总是我真正想要的
s
saille

此扩展方法将使用其 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;
}

R
Ranco

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

    [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");
    }
}

希望能帮助到你


M
MeTitus

如果你想要完整的名字列表,你可以做类似的事情

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

O
Onur Dikmen

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

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

    }

P
Parvez Ali

我创建了一个扩展方法,它将返回 C# 枚举中所有元素的描述。

public static List<string> GetAllEnumDescriptions(this Type enumType)
    {
        try
        {
            var enumList = Enum.GetValues(enumType).Cast<Enum>().ToList();
            List<string> result = new List<string>();
            foreach (var enumItem in enumList)
            {
                result.Add(enumItem.EnumDescription());
            }
            return result;
        }
        catch (Exception ex)
        {
            return new List<string>();
        }
    }

此方法将使用内置的 EnumDescription() 扩展方法在枚举中添加元素的描述。


A
Aramean

这就是我在不使用 .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>
}

考虑使用比你如何解决“它”更多的方式来回答问题 - 首先承认问题并解释你认为这如何解决“它”。请记住,从现在开始的几年内,您的答案可能会断章取义,然后几乎没有用。添加更多内容,添加一些上下文将提高您的答案及其可能的历史/档案相关性