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

using System.ComponentModel; // for DescriptionAttribute

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

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

价值很简单:

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

但我如何获得描述属性的值,以填充Tuple.Desc?如果属性属于枚举本身,我可以想到如何做到这一点,但我不知道如何从枚举的值中获得它。


当前回答

模型

我们用这个模型来充实我们的价值观

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

Enum

我们的目标是枚举

public enum MemberType
{
    [FieldText("Yönetim Kurul Üyesi")]
    BoardManager = 0,

    [FieldText("Temsilci")]
    Representative = 1,

    [FieldText("Üye")]
    Member = 2
}

辅助方法

我们将使用helper方法来获取自定义属性对象

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

Get方法

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

MemberAttributeName字段与helper方法, 带有Enum的MemberName字段。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;
}

其他回答

这段代码应该为任何枚举提供了一个不错的扩展方法,使您可以检索泛型属性。我相信它与上面的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<DescriptionAttribute>().Description;

这就是我在不使用。net core 3.1的自定义helper或扩展的情况下解决它的方法。

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

如果你的枚举包含一个像Equals这样的值,你可能会在很多答案中使用一些扩展遇到一些错误。这是因为通常假设typeof(YourEnum). getmember (YourEnum. value)将只返回一个值,即枚举的MemberInfo。这是一个稍微安全一点的亚当·克劳福德的回答。

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
}

性能问题

如果你想要更好的性能,这是一种方法:

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化和精简,所以它只包含我们关心的部分。

为什么内置代码很慢?

首先关于枚举. tostring () -vs-枚举. getname (..)

总是使用后者。(或者两者都不做更好,如下文将会清楚说明。)

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

枚举。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;
        }