[C#] Enum 값의 속성 얻기

그 자체가 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있습니다.



답변

필요한 작업을 수행해야합니다.

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;


답변

이 코드는 일반 속성을 검색 할 수있는 열거 형에 멋진 확장 방법을 제공해야합니다. 사용하기가 간단하고 약간이기 때문에 위의 람다 함수와 다르다고 생각합니다. 일반 유형 만 전달하면됩니다.

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


답변

이것은 선택을 위해 람다를 사용하는 일반적인 구현입니다.

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


답변

좀 더 확장 가능한 솔루션을 만들기 위해 여기에 몇 가지 답변을 병합했습니다. 앞으로 다른 사람에게 도움이 될 경우를 대비하여 제공하고 있습니다. 원래 게시물은 여기에 있습니다 .

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.

예를 들어, DescriptionAttributefrom 속성을 사용해보십시오System.ComponentModel

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


답변

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

희망적으로 코드를 좀 더 읽기 쉽게 만들어야합니다.


답변

유창한 라이너 …

여기서는 및 속성 DisplayAttribute이 모두 포함 된를 사용 Name하고 Description있습니다.

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


답변

다음은 Display 속성에서 정보를 얻는 코드입니다. 일반 메소드를 사용하여 속성을 검색합니다. 속성을 찾지 못하면 열거 형 값을 pascal / camel case를 title case로 변환 한 문자열로 변환합니다 ( 여기서 얻은 코드 )

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