如何读取 EnumMember 属性的值

问题描述 投票:0回答:10
public enum Status
    {

        Pending,
        [EnumMember(Value = "In Progress")]
        InProgress,
        Failed,
        Success
    }

string dbValue = "In Progress";
if (dbValue == ValueOf(Status.InProgress)){
//do some thing
}

如何读取 Status.InProgress 的值以便返回“进行中”?

c# attributes
10个回答
41
投票

这是一个适用于 C# 8 和可为空引用类型的扩展方法:

public static string? GetEnumMemberValue<T>(this T value)
    where T : Enum
{
    return typeof(T)
        .GetTypeInfo()
        .DeclaredMembers
        .SingleOrDefault(x => x.Name == value.ToString())
        ?.GetCustomAttribute<EnumMemberAttribute>(false)
        ?.Value;
}

原答案:

我已针对 .NET Core 进行了调整。这是:

public static String GetEnumMemberValue<T>(T value)
    where T : struct, IConvertible
{
    return typeof(T)
        .GetTypeInfo()
        .DeclaredMembers
        .SingleOrDefault(x => x.Name == value.ToString())
        ?.GetCustomAttribute<EnumMemberAttribute>(false)
        ?.Value;
}

27
投票

类似这样的:

public string GetEnumMemberAttrValue(Type enumType, object enumVal)
{
      var memInfo = enumType.GetMember(enumVal.ToString());
      var attr = memInfo[0].GetCustomAttributes(false).OfType<EnumMemberAttribute>().FirstOrDefault();
      if(attr != null)
      {
          return attr.Value;
      }

      return null;
}

用途:

var enumType = typeof(Status);
var enumVal = Status.InProgress;
var str = GetEnumMemberAttrValue(enumType,enumVal);

17
投票

借用阿米尔的答案,可以使用泛型得到一个稍微好一点的版本,如下所示:

public string GetEnumMemberAttrValue<T>(T enumVal)
{
    var enumType = typeof(T);
    var memInfo = enumType.GetMember(enumVal.ToString());
    var attr = memInfo.FirstOrDefault()?.GetCustomAttributes(false).OfType<EnumMemberAttribute>().FirstOrDefault();
    if (attr != null)
    {
        return attr.Value;
    }

    return null;
}

使用方法如下:

var enumVal = Status.InProgress;
var str = GetEnumMemberAttrValue(enumVal);

据我所知,不能使用 where 子句将 T 限制为枚举。不过,我很乐意得到纠正。


15
投票

将其包裹在扩展中,使其感觉更自然:

public static class Extension
{
    public static string ToEnumMemberAttrValue(this Enum @enum)
    {
        var attr = 
            @enum.GetType().GetMember(@enum.ToString()).FirstOrDefault()?.
                GetCustomAttributes(false).OfType<EnumMemberAttribute>().
                FirstOrDefault();
        if (attr == null)
            return @enum.ToString();
        return attr.Value;
    }
}

用途:

string dbValue = "In Progress";
if (dbValue == Status.ToEnumMemberAttrValue())){
    //do some thing
}

8
投票

如果您的项目中有 Newtonsoft,那么您应该这样做:

对于 Enum,您应该添加属性 [JsonConverter(typeof(StringEnumConverter))]

现在您可以调用 JsonConvertor 将您的值序列化为成员字符串值。

在你的例子中,应该是这样的

[JsonConverter(typeof(StringEnumConverter))]
public enum Status
{

    Pending,
    [EnumMember(Value = "In Progress")]
    InProgress,
    Failed,
    Success
}

string dbValue = "In Progress";
if (dbValue == JsonConvert.SerializeObject(Status.InProgress)){
//do some thing
}

请注意,@Dinesh 在评论中提到,该字符串是 JSON,因此使用 quatos 返回,因此您可以解决该问题,以使用 strin.Replace 方法获取干净的字符串:

dbValue == JsonConvert.SerializeObject(Status.InProgress).Replace("\"","");

4
投票

到目前为止发布的所有方法的一个问题是,它们每次查找都使用

GetCustomAttribute<EnumMemberAttribute>
,这有点昂贵。

鉴于从反射加载的属性是不可变的,对于正在查找的每个枚举类型 (

GetCustomAttribute<>
),将
TEnum
结果缓存在内存中是有意义的。

A

static class<T>
T
上的通用对象,具有静态初始化器,有效地充当每个 T
 的单例 
,可用于拥有
ImmutableDictionary
来高效地 和延迟 缓存枚举成员属性数据:

因为下面的代码是通用的

TEnum : struct, Enum
,这意味着也没有枚举值装箱并且它支持不同底层类型的枚举(例如
enum Foo : int
enum Bar : long
等):

public static class EnumMemberNames
{
    public static String? GetNameOrNull<TEnum>( TEnum value )
        where TEnum : struct, Enum
    {
        return EnumAttribCache<TEnum>.cachedNames.TryGetValue( value, out String? text ) ? text : null;
    }

    public static String GetName<TEnum>( TEnum value )
        where TEnum : struct, Enum
    {
        return GetNameOrNull( value ) ?? value.ToString();
    }

    private static class EnumAttribCache<TEnum>
        where TEnum : struct, Enum
    {
        public static readonly ImmutableDictionary<TEnum,String> cachedNames = LoadNames();

        private static ImmutableDictionary<TEnum,String> LoadNames()
        {
            return typeof(TEnum)
                .GetTypeInfo()
                .DeclaredFields
                .Where( f => f.IsStatic && f.IsPublic && f.FieldType == typeof(TEnum) )
                .Select( f => ( field: f, attrib: f.GetCustomAttribute<EnumMemberAttribute>() ) )
                .Where( t => ( t.attrib?.IsValueSetExplicitly ?? false ) && !String.IsNullOrEmpty( t.attrib.Value ) )
                .ToDictionary(
                    keySelector    : t => (TEnum)t.field.GetValue( obj: null )!,
                    elementSelector: t => t.attrib!.Value!
                )
                .ToImmutableDictionary();
        }
    }
}

像这样使用:

enum Foo
{
    [EnumMemberAttribute( Value = "first" )]
    A = 1,

    [EnumMemberAttribute( Value = "second" )]
    B = 2,

    Unnamed = 4
}

public static void Main()
{
    Console.WriteLine( EnumMemberNames.GetNameOrNull( Foo.A ) ); // "first"
    Console.WriteLine( EnumMemberNames.GetNameOrNull( Foo.B ) ); // "second"
    Console.WriteLine( EnumMemberNames.GetName( Foo.Unnamed ) ); // "Unnamed"
}

3
投票
    public static object GetMemberAttr(this Enum enumItem)
    {
        var memInfo = enumItem.GetType().GetMember(enumItem.ToString());
        var attr = memInfo[0].GetCustomAttributes(false);
        return attr == null || attr.Length == 0 ? null :((System.Runtime.Serialization.EnumMemberAttribute) attr[0]).Value;
    }

用法:{YouEnum}.{EnumItem}.GetMemberAttr() 公共枚举 TEST_ENUM { [EnumMember(值=“1分钟”)] 分钟, [EnumMember(值 = "2min")] 2分钟, [EnumMember(值 = "3min")] 三分钟, }

公共 TEST_ENUM t;

? t.TwoMinutes.GetMemberAttr()
2分钟


1
投票

试试这个,

var type = typeof(YourEnum);
var Info = type.GetMember(YourEnum.attribute); // pass enum item here
string enumdescription = Info[0].CustomAttributes.SingleOrDefault().NamedArguments[0].TypedValue.ToString();

1
投票

[EnumMember]
属性由 Newtonsoft 等序列化器使用。

System.Runtime.Serialization
(命名空间)

EnumMemberAttribute
(班级)

枚举:

public enum Status
{
    Pending,
    [EnumMember(Value = "In Progress")]
    InProgress,
    Failed,
    Success
}

示例代码:

string databaseValue = "In Progress";

// Serialize the enum value
string statusValue = Newtonsoft.Json.JsonConvert.SerializeObject(Status.InProgress);

if  (statusValue.Contains(databaseValue))
{
    // Do something
}

0
投票

编写了一个简单的扩展方法。

public static class EnumExtensions
{
    public static string ToEnumMememberAttributeValue(this Enum value)
    {
       var enumType = value.GetType();
       var enumMemeberAttribute = enumType
        .GetTypeInfo()
        .DeclaredMembers
        .Single(x => x.Name == value.ToString())
        .GetCustomAttribute<EnumMemberAttribute>(false);

        if (enumMemeberAttribute == null)
        {
            throw new NotSupportedException($"Enum: '{enumType.FullName}', value: {value} does not have attribute: '{nameof(EnumMemberAttribute)}'.");
        }

        return enumMemeberAttribute.Value;
    }

}

© www.soinside.com 2019 - 2024. All rights reserved.