580 Stimmen

Attribute des Enum-Wertes abrufen

Ich würde gerne wissen, ob es möglich ist, Attribute der enum Werte und nicht der enum selbst? Angenommen, ich habe zum Beispiel folgendes enum :

using System.ComponentModel; // for DescriptionAttribute

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

Was ich will, ist der Enum-Typ gegeben, produzieren 2-Tupel von Enum-String-Wert und seine Beschreibung.

Der Wert war einfach:

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

Aber wie erhalte ich den Wert des Attributs description, um die Tuple.Desc ? Ich kann mir vorstellen, wie man es macht, wenn das Attribut zum enum selbst, aber ich weiß nicht, wie ich ihn aus dem Wert der enum .

0 Stimmen

Aus einer anderen Frage stackoverflow.com/questions/469287/

3 Stimmen

Der für die Beschreibung erforderliche Namespace ist System.ComponentModel

24voto

Aydin Punkte 14156

Fließende Einzeiler...

Hier verwende ich die DisplayAttribute die sowohl die Name y Description Eigenschaften.

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

Beispiel

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

7voto

Colin Punkte 21707

Hier ist Code zum Abrufen von Informationen aus einem Display-Attribut. Er verwendet eine generische Methode zum Abrufen des Attributs. Wenn das Attribut nicht gefunden wird, wird der Enum-Wert in eine Zeichenkette umgewandelt, wobei die Groß-/Kleinschreibung in Groß- und Kleinschreibung umgewandelt wird (der erhaltene Code aquí )

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

Und dies ist die Erweiterungsmethode für Strings zur Konvertierung in Groß- und Kleinschreibung:

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

5voto

AnorZaken Punkte 1637

Leistung zählt

Wenn Sie eine bessere Leistung wünschen, ist dies der richtige Weg:

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

Warum ist die Leistung so besser?

Denn die eingebauten Methoden verwenden alle einen ähnlichen Code, außer sie führen auch einen Haufen anderen Code aus, der uns nicht interessiert . Der Enum-Code von C# ist im Allgemeinen ziemlich schrecklich.

Der obige Code wurde in Linq umgewandelt und gestrafft, so dass er nur die für uns wichtigen Teile enthält.

Warum ist der integrierte Code langsam?

Zunächst zu Enum.ToString() -vs- Enum.GetName(..)

Verwenden Sie immer Letzteres. (Oder besser keine, wie weiter unten deutlich wird.)

ToString() verwendet letzteres intern, macht aber auch wieder eine Menge anderer Dinge, die wir nicht wollen, z.B. versucht, Flags zu kombinieren, Zahlen auszugeben usw. Wir sind nur an den Konstanten interessiert, die innerhalb der Enum definiert sind.

Enum.GetName holt wiederum alle Felder ab, erstellt ein String-Array für alle Namen, verwendet das obige ToUInt64 auf alle RawConstantValues, um ein UInt64-Array mit allen Werten zu erstellen, sortiert beide Arrays nach dem UInt64-Wert und holt schließlich den Namen aus dem Name-Array, indem es eine BinarySearch im UInt64-Array durchführt, um den Index des gewünschten Wertes zu finden.

...und dann werfen wir die Felder und die sortierten Arrays weg und verwenden diesen Namen, um das Feld wieder zu finden.

Ein Wort: "Igitt!"

5voto

Prince Owen Punkte 526

Wenn Ihr enum enthält einen Wert wie Equals Sie könnten in vielen Antworten hier auf einige Fehler stoßen, wenn Sie einige Erweiterungen verwenden. Dies liegt daran, dass normalerweise angenommen wird, dass typeof(YourEnum).GetMember(YourEnum.Value) würde nur einen Wert zurückgeben, nämlich den MemberInfo Ihrer enum . Hier ist eine etwas sicherere Version Adam Crawfords Antwort .

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
}

5voto

Jinjinov Punkte 2202

Für etwas Programmierer-Humor, ein One-Liner als Witz:

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

In einer besser lesbaren Form:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X