Wie erhalte ich das Anzeigenamenattribut eines Enum-Mitglieds über MVC-Rasiermessercode?

211

Ich habe eine Eigenschaft in meinem Modell namens "Promotion", deren Typ eine Flaggenaufzählung namens "UserPromotion" ist. Mitglieder meiner Aufzählung haben folgende Anzeigeattribute:

[Flags]
public enum UserPromotion
{
    None = 0x0,

    [Display(Name = "Send Job Offers By Mail")]
    SendJobOffersByMail = 0x1,

    [Display(Name = "Send Job Offers By Sms")]
    SendJobOffersBySms = 0x2,

    [Display(Name = "Send Other Stuff By Sms")]
    SendPromotionalBySms = 0x4,

    [Display(Name = "Send Other Stuff By Mail")]
    SendPromotionalByMail = 0x8
}

Jetzt möchte ich in meiner Ansicht beispielsweise eine ul erstellen können, um die ausgewählten Werte meiner Eigenschaft "Promotion" anzuzeigen. Dies ist, was ich bisher getan habe, aber das Problem ist, wie kann ich die Anzeigenamen hier erhalten?

<ul>
    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
    {
        var currentPromotion = (int)Model.JobSeeker.Promotion;
        if ((currentPromotion & aPromotion) == aPromotion)
        {
        <li>Here I don't know how to get the display attribute of "currentPromotion".</li>
        }
    }
</ul>
Pejman
quelle
12
MVC5 unterstützt das DisplayName-Attribut für Aufzählungen.
Bart Calixto
10
Um es klarer zu machen: Nur System.ComponentModel.DataAnnotations.DisplayAttribute. Nicht System.ComponentModel.DisplayNameAttribute.
Kamranicus
1
Umfasst dies die Verwendung von Reflexion und wirkt sich daher auf die Leistung aus? Weil das eine Menge Zeit genannt wird.
Nico

Antworten:

182

AKTUALISIEREN

Die erste Lösung konzentrierte sich darauf, Anzeigenamen von enum zu erhalten. Der folgende Code sollte die genaue Lösung für Ihr Problem sein.

Sie können diese Hilfsklasse für Aufzählungen verwenden:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}

Und dann können Sie es in Ihrer Ansicht wie folgt verwenden:

<ul>
    @foreach (var value in @EnumHelper<UserPromotion>.GetValues(UserPromotion.None))
    {
         if (value == Model.JobSeeker.Promotion)
        {
            var description = EnumHelper<UserPromotion>.GetDisplayValue(value);
            <li>@Html.DisplayFor(e => description )</li>
        }
    }
</ul>

Ich hoffe es hilft! :) :)

Hrvoje Stanisic
quelle
8
Alle Antworten werden verwendet .ToString, aber von stackoverflow.com/q/483794/179311 heißt es, Enum.GetNamestattdessen zu verwenden .
Bradlis7
value.GetType (). GetField (value.ToString ()) war genau das, wonach ich gesucht habe!
cdie
Diese Antwort ist mit einigen zusätzlichen Nullprüfungen in Ordnung , aber wenn Sie keine Punktfuskierung verwenden, scheint die Antwort unter stackoverflow.com/a/4412730/852806 einfacher zu sein.
HockeyJ
5
In GetDisplayValuesollten Sie zuerst testen, descriptionAttributes == nullbevor Sie versuchen, auf das Array zuzugreifen : descriptionAttributes[0]. Andernfalls können Sie eine Ausnahme auslösen, und die Zeile darunter, in der Sie nach Null suchen, ist niemals wahr.
Robert S.
Ich würde kleinere Änderungen vorschlagen: public static IList <T> GetValues ​​(Enum-Wert) könnte public static IList <T> GetValues ​​(T-Wert) sein. EnumHelper <T> to => öffentliche statische Klasse EnumHelper <T> wobei T: struct, IConvertible. Vielleicht statischer Konstruktor? statisch EnumHelper () {if (! typeof (T) .IsEnum) {neue ArgumentException auslösen ("T muss ein Aufzählungstyp sein"); }}
Tom
172

Einzeiler - Fließende Syntax

public static class Extensions
{
    /// <summary>
    ///     A generic extension method that aids in reflecting 
    ///     and retrieving any attribute that is applied to an `Enum`.
    /// </summary>
    public static TAttribute GetAttribute<TAttribute>(this Enum enumValue) 
            where TAttribute : Attribute
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<TAttribute>();
    }
}

Beispiel

public enum Season 
{
   [Display(Name = "It's autumn")]
   Autumn,

   [Display(Name = "It's winter")]
   Winter,

   [Display(Name = "It's spring")]
   Spring,

   [Display(Name = "It's summer")]
   Summer
}

public class Foo 
{
    public Season Season = Season.Summer;

    public void DisplayName()
    {
        var seasonDisplayName = Season.GetAttribute<DisplayAttribute>();
        Console.WriteLine("Which season is it?");
        Console.WriteLine (seasonDisplayName.Name);
    } 
}

Ausgabe

Welche Jahreszeit ist es?
Es ist Sommer

Aydin
quelle
2
Es gibt keine Definition von GetCustomAttribute
Tito
3
@Tito stellen Sie sicher, dass Ihr Projekt ausgerichtet ist .NET Framework 4.5und dass Sie die folgenden Namespaces einschließenSystem.Net System.ComponentModel.DataAnnotations
Aydin
8
using System.Reflection; using System.ComponentModel.DataAnnotations; Wurde für mich gebraucht.
Sinned Lolwut
1
Was für eine schreckliche Namenskonvention!
neugierigBoy
@curiousBoy Wie ist GetAttribute<TAttribute>eine schreckliche Namenskonvention? Es ruft das von Ihnen angegebene Attribut ab und verwendet das Pascal-Gehäuse wie alle öffentlichen Methoden.
Aydin
137

Aufbauend auf Aydins großartiger Antwort finden Sie hier eine Erweiterungsmethode, für die keine Typparameter erforderlich sind.

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<DisplayAttribute>()
                        .GetName();
    }
}

HINWEIS : GetName () sollte anstelle der Name-Eigenschaft verwendet werden. Dadurch wird sichergestellt, dass die lokalisierte Zeichenfolge zurückgegeben wird, wenn die Attributeigenschaft ResourceType verwendet wird.

Beispiel

Um es zu verwenden, verweisen Sie einfach auf den Aufzählungswert in Ihrer Ansicht.

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

Ausgabe

Promotion: Stellenangebote per Mail verschicken

Todd
quelle
4
Außerdem können Sie die folgenden Namespaces hinzufügen: using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection;
Peter Kerr
Kluge Lösung, aber ich bekomme {"Vorlagen können nur mit Feldzugriff, Eigenschaftszugriff, eindimensionalem Array-Index oder benutzerdefinierten Indexerausdrücken mit einzelnen Parametern verwendet werden."}
Casey Crookston
Wenn Sie sich andere SO-Antworten für diese Fehlermeldung ansehen (ich bin damit nicht vertraut), scheint es, dass Sie diese innerhalb einer HTML-Hilfsmethode verwenden (wie @Html.DisplayFor(m => m.myEnum.GetDisplayName())dies nicht funktioniert, da erwartet wird, dass der ausgewertete Ausdruck eine Eigenschaft ergibt oder etwas Ähnliches. Sie sollten den nackten Aufzählungswert wie im obigen Beispiel verwenden.
Todd
7
Ich habe dem Ergebnis eine Null-Referenzprüfung hinzugefügt, GetCustomAttribute<DisplayAttribute>()da dies für einige Enums möglicherweise nicht vorhanden ist. Es wird darauf zurückgegriffen, enumValue.ToString()ob das DisplayAttribute nicht vorhanden war.
H Hund
1
Ich habe dies verwendet, um eine zu erstellen List<SelectListItem>, die von einer Aufzählung mit allen einzelnen DisplayAttribute.NameAnmerkungen gefüllt wurde - dies hat perfekt funktioniert, danke !! public List<SelectListItem> MySelectListItem = new List<SelectListItem>(); foreach (MyEnum MyEnum in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Where(x => x != MyEnum.Default)) { MySelectListItem.Add(new SelectListItem() { Text = MyEnum.GetDisplayName(), Value = ((int)MyEnum).ToString() }); }
Hopper
61

Basierend auf Aydins Antwort würde ich eine weniger "doppelte" Implementierung vorschlagen (da wir das leicht Typeaus dem EnumWert selbst erhalten könnten , anstatt es als Parameter bereitzustellen 😉:

public static string GetDisplayName(this Enum enumValue)
{
    return enumValue.GetType().GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DisplayAttribute>()
                   .Name;
}

BEARBEITEN (basierend auf dem Kommentar von @Vahagn Nahapetyan)

public static string GetDisplayName(this Enum enumValue)
{
    return enumValue.GetType()?
                    .GetMember(enumValue.ToString())?
                    .First()?
                    .GetCustomAttribute<DisplayAttribute>()?
                    .Name;
}

Jetzt können wir es auf diese Weise sehr sauber verwenden:

public enum Season 
{
    [Display(Name = "The Autumn")]
    Autumn,

    [Display(Name = "The Weather")]
    Winter,

    [Display(Name = "The Tease")]
    Spring,

    [Display(Name = "The Dream")]
    Summer
}

Season.Summer.GetDisplayName();

Was in ... endet

"Der Traum"

Bernoulli IT
quelle
1
Mit Abstand die einfachste und einfachste aller Antworten. Vielen Dank!
Casey Crookston
Sie sollten mit .First () vorsichtig sein. Dies wird eine Ausnahme
auslösen,
Ich verstehe die "Gefahr" mit First (). In diesem speziellen Fall scheint es kein Problem zu sein. Da es sich um eine Erweiterungsmethode handelt, bei thisder ein gültiger (nicht null) Enum-Wert angegeben werden muss. Andernfalls würde der Aufruf der Methode bereits auslösen (was in der Verantwortung des aufrufenden Codes liegt). Dadurch GetType()wird mit Sicherheit der richtige Aufzählungstyp bereitgestellt, in dem Sie enumvaluemit Sicherheit Mitglied sein werden. Da GetCustomAttribute jedoch möglicherweise einen Nullwert zurückgibt, habe ich eine nicht außergewöhnliche Version der Methode bereitgestellt, um Null zurückzugeben, wenn die Kette von Methodenaufrufen irgendwo einen Null-Rückgabewert hat. Vielen Dank!
Bernoulli IT
1
Für die zweite Variante Ihres Codes scheint es nicht erforderlich zu sein, nach GetMember einen nullbedingten Operator zu verwenden, da diese Methode immer ein Array von MemberInfo zurückgibt und niemals null zurückgibt. Und für mich scheint es besser zu sein, FirstOrDefault anstelle von First zu verwenden. Dann wird die Verwendung des nullbedingten Operators nach FirstOrDefault als konsistent angesehen.
Alex34758
28

Wenn Sie MVC 5.1 oder höher verwenden, gibt es eine einfachere und klarere Möglichkeit: Verwenden Sie einfach die Datenanmerkung (aus dem System.ComponentModel.DataAnnotationsNamespace) wie folgt :

public enum Color
{
    [Display(Name = "Dark red")]
    DarkRed,
    [Display(Name = "Very dark red")]
    VeryDarkRed,
    [Display(Name = "Red or just black?")]
    ReallyDarkRed
}

Und in Sicht, setzen Sie es einfach in den richtigen HTML-Helfer:

@Html.EnumDropDownListFor(model => model.Color)
1_bug
quelle
@ SegmentationFault warum? Können Sie Ihr Problem beschreiben? Welche Version von .NET / MVC verwenden Sie? Welchen Fehler hast du? Bitte sei spezifischer.
1_bug
6
Weil es nur für Dropdowns funktioniert, nirgendwo anders.
Segmentierungsfehler
2
Scheint
3
.net Core verwendet Html.GetEnumSelectList (typeof (YourEnum)) @Lonefish
Patrick Mcvay
2
Wenn wir @ Html.DisplayFor (yourEnumField) verwenden möchten, können wir eine Enum.cshtml in das DisplayTemplates-Verzeichnis (im freigegebenen Verzeichnis) einfügen. In dieser Datei müssen nur 2 Zeilen eingefügt werden. Das erste ist: "@model Enum", das zweite ist: "@GetDisplayName (Model)". Die GetDisplayName-Methode muss wie in @Bernoulli IT answare
Developer
11

Sie können die Type.GetMember-Methode verwenden und dann die Attributinformationen mithilfe von Reflection abrufen :

// display attribute of "currentPromotion"

var type = typeof(UserPromotion);
var memberInfo = type.GetMember(currentPromotion.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var description = ((DisplayAttribute)attributes[0]).Name;

Es gab hier einige ähnliche Beiträge:

Attribute des Enum-Werts abrufen

Wie kann MVC3 DisplayFor den Wert des Anzeigeattributs einer Enum anzeigen?

maximpa
quelle
8

Aufbauend auf der großartigen Antwort von Todd, die auf der großartigen Antwort von Aydin aufbaut , finden Sie hier eine generische Erweiterungsmethode, für die keine Typparameter erforderlich sind.

/// <summary>
/// Gets human-readable version of enum.
/// </summary>
/// <returns>DisplayAttribute.Name property of given enum.</returns>
public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Argument must be of type Enum");

    DisplayAttribute displayAttribute = enumValue.GetType()
                                                 .GetMember(enumValue.ToString())
                                                 .First()
                                                 .GetCustomAttribute<DisplayAttribute>();

    string displayName = displayAttribute?.GetName();

    return displayName ?? enumValue.ToString();
}

Ich brauchte dies für mein Projekt, weil so etwas wie der folgende Code, in dem nicht jedes Mitglied der Enumeration einen hat DisplayAttribute, nicht mit der Lösung von Todd funktioniert:

public class MyClass
{
    public enum MyEnum 
    {
        [Display(Name="ONE")]
        One,
        // No DisplayAttribute
        Two
    }
    public void UseMyEnum()
    {
        MyEnum foo = MyEnum.One;
        MyEnum bar = MyEnum.Two;
        Console.WriteLine(foo.GetDisplayName());
        Console.WriteLine(bar.GetDisplayName());
    }
}
// Output:
//
// ONE
// Two

Wenn dies eine komplizierte Lösung für ein einfaches Problem ist, lassen Sie es mich bitte wissen, aber dies war die Lösung, die ich verwendet habe.

Sinjai
quelle
6
<ul>
    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
    {
        var currentPromotion = (int)Model.JobSeeker.Promotion;
        if ((currentPromotion & aPromotion) == aPromotion)
        {
        <li>@Html.DisplayFor(e => currentPromotion)</li>
        }
    }
</ul>
Dmytro
quelle
Funktioniert nicht: / Ich InvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
erhalte
6

Ich habe zwei Lösungen für diese Frage.

  1. Die erste Lösung besteht darin, Anzeigenamen aus enum abzurufen.
public enum CourseLocationTypes
{
    [Display(Name = "On Campus")]
    OnCampus,
    [Display(Name = "Online")]
    Online,
    [Display(Name = "Both")]
    Both
}

public static string DisplayName(this Enum value)
{
    Type enumType = value.GetType();
    string enumValue = Enum.GetName(enumType, value);
    MemberInfo member = enumType.GetMember(enumValue)[0];

    object[] attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
    string outString = ((DisplayAttribute)attrs[0]).Name;

    if (((DisplayAttribute)attrs[0]).ResourceType != null)
    {
        outString = ((DisplayAttribute)attrs[0]).GetName();
    }

    return outString;
}
<h3 class="product-title white">@Model.CourseLocationType.DisplayName()</h3>
  1. Die zweite Lösung besteht darin, den Anzeigenamen vom Namen der Aufzählung abzurufen, diese wird jedoch in der Entwicklersprache aufgeteilt, die als Patch bezeichnet wird.
public static string SplitOnCapitals(this string text)
{
        var r = new Regex(@"
            (?<=[A-Z])(?=[A-Z][a-z]) |
             (?<=[^A-Z])(?=[A-Z]) |
             (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);

        return r.Replace(text, " ");
}
 <div class="widget-box pt-0">
     @foreach (var item in Enum.GetNames(typeof(CourseLocationType)))
     {
         <label class="pr-2 pt-1">
             @Html.RadioButtonFor(x => x.CourseLocationType, item, new { type = "radio", @class = "iCheckBox control-label" })&nbsp; @item.SplitOnCapitals()
         </label>
     }
     @Html.ValidationMessageFor(x => x.CourseLocationType)
 </div>
Yasin Sunnit
quelle
5

Für ASP.Net Core 3.0 hat dies bei mir funktioniert (Gutschrift an frühere Antwortende).

Meine Enum-Klasse:

using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

public class Enums
{
    public enum Duration
    { 
        [Display(Name = "1 Hour")]
        OneHour,
        [Display(Name = "1 Day")]
        OneDay
    }

    // Helper method to display the name of the enum values.
    public static string GetDisplayName(Enum value)
    {
        return value.GetType()?
       .GetMember(value.ToString())?.First()?
       .GetCustomAttribute<DisplayAttribute>()?
       .Name;
    }
}

Meine Ansicht Modellklasse:

public class MyViewModel
{
    public Duration Duration { get; set; }
}

Ein Beispiel für eine Rasiereransicht mit einer Beschriftung und einer Dropdown-Liste. Beachten Sie, dass für die Dropdown-Liste keine Hilfsmethode erforderlich ist:

@model IEnumerable<MyViewModel> 

@foreach (var item in Model)
{
    <label asp-for="@item.Duration">@Enums.GetDisplayName(item.Duration)</label>
    <div class="form-group">
        <label asp-for="@item.Duration" class="control-label">Select Duration</label>
        <select asp-for="@item.Duration" class="form-control"
            asp-items="Html.GetEnumSelectList<Enums.Duration>()">
        </select>
    </div>
}
Meer Ozean
quelle
Ich würde eine Überprüfung der GetDisplayName-Methode hinzufügen. Return string.IsNullOrEmpty (retVal)? enumValue.ToString (): retVal;
Sniipe
4

Sie müssen ein wenig nachdenken, um auf dieses Attribut zugreifen zu können:

var type = typeof(UserPromotion);
var member = type.GetMember(Model.JobSeeker.Promotion.ToString());
var attributes = member[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var name = ((DisplayAttribute)attributes[0]).Name;

Ich empfehle, diese Methode in eine Erweiterungsmethode einzuschließen oder in einem Ansichtsmodell auszuführen.

alexn
quelle
4

Mit Core 2.1,

public static string GetDisplayName(Enum enumValue)
{
  return enumValue.GetType()?
 .GetMember(enumValue.ToString())?[0]?
 .GetCustomAttribute<DisplayAttribute>()?
 .Name;
}
Deniz aydın
quelle
4

Kombinieren aller Randfälle von oben:

  • Enum-Mitglieder mit den Namen der Basisobjektmitglieder ( Equals, ToString)
  • optionales DisplayAttribut

Hier ist mein Code:

public enum Enum
{
    [Display(Name = "What a weird name!")]
    ToString,

    Equals
}

public static class EnumHelpers
{
    public static string GetDisplayName(this Enum enumValue)
    {
        var enumType = enumValue.GetType();

        return enumType
                .GetMember(enumValue.ToString())
                .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == enumType)
                .First()
                .GetCustomAttribute<DisplayAttribute>()?.Name ?? enumValue.ToString();
    }
}

void Main()
{
    Assert.Equals("What a weird name!", Enum.ToString.GetDisplayName());
    Assert.Equals("Equals", Enum.Equals.GetDisplayName());
}
avs099
quelle
Schöne Lösung, die das optionale Display-Attribut behandelt. Vielen Dank!
Wellspring
3

Es tut mir leid, dies zu tun, aber ich konnte keine der anderen Antworten so wie sie sind verwenden und habe keine Zeit, sie in den Kommentaren herauszuarbeiten.

Verwendet die C # 6-Syntax.

static class EnumExtensions
{
    /// returns the localized Name, if a [Display(Name="Localised Name")] attribute is applied to the enum member
    /// returns null if there isnt an attribute
    public static string DisplayNameOrEnumName(this Enum value)
    // => value.DisplayNameOrDefault() ?? value.ToString()
    {
        // More efficient form of ^ based on http://stackoverflow.com/a/17034624/11635
        var enumType = value.GetType();
        var enumMemberName = Enum.GetName(enumType, value);
        return enumType
            .GetEnumMemberAttribute<DisplayAttribute>(enumMemberName)
            ?.GetName() // Potentially localized
            ?? enumMemberName; // Or fall back to the enum name
    }

    /// returns the localized Name, if a [Display] attribute is applied to the enum member
    /// returns null if there is no attribute
    public static string DisplayNameOrDefault(this Enum value) =>
        value.GetEnumMemberAttribute<DisplayAttribute>()?.GetName();

    static TAttribute GetEnumMemberAttribute<TAttribute>(this Enum value) where TAttribute : Attribute =>
        value.GetType().GetEnumMemberAttribute<TAttribute>(value.ToString());

    static TAttribute GetEnumMemberAttribute<TAttribute>(this Type enumType, string enumMemberName) where TAttribute : Attribute =>
        enumType.GetMember(enumMemberName).Single().GetCustomAttribute<TAttribute>();
}
Ruben Bartelink
quelle
2

Aufbauend auf den Antworten von Aydin und Todd finden Sie hier eine Erweiterungsmethode, mit der Sie auch den Namen aus einer Ressourcendatei abrufen können

using AppResources;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Resources;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        var enumMember= enumValue.GetType()
                        .GetMember(enumValue.ToString());

        DisplayAttribute displayAttrib = null;
        if (enumMember.Any()) {
            displayAttrib = enumMember 
                        .First()
                        .GetCustomAttribute<DisplayAttribute>();
        }

        string name = null;
        Type resource = null;

        if (displayAttrib != null)
        {
            name = displayAttrib.Name;
            resource = displayAttrib.ResourceType;
        }

        return String.IsNullOrEmpty(name) ? enumValue.ToString()
            : resource == null ?  name
            : new ResourceManager(resource).GetString(name);
    }
}

und benutze es gerne

public enum Season 
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}
Peter Kerr
quelle
Ich versuche, dies für mein Projekt zum Laufen zu bringen, erhalte jedoch eine Fehlermeldung mit dem "neuen ResourceManager (Ressource) .GetString (Name);" Linie. Ich hatte eine Frage gestellt ( stackoverflow.com/questions/31319251/… ) und wurde hierher geschickt. Wenn ich den "ResourceManager (Ressource)" während der Ausführung ansehe, wird "Resources.Enums.resource" zurückgegeben. Jede Hilfe wäre sehr dankbar. Danke dir!
Karinne
Der Code wurde aktualisiert, um Nullen besser behandeln zu können, wenn für einige der Aufzählungswerte kein Anzeigename festgelegt wurde - möglicherweise hilfreich
Peter Kerr
Das hat immer noch nicht funktioniert. Ich habe meine Frage unter stackoverflow.com/questions/31319251/… mit der Fehlermeldung aktualisiert . Danke für die Hilfe!
Karinne
1

Ich möchte mit der kulturabhängigen Enum-Erweiterung GetDisplayName einen Beitrag leisten. Ich hoffe, dies ist nützlich für alle, die diese Antwort wie ich zuvor googeln:

"Standard" Weg, wie Aydin Adn und Todd erwähnten:

    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue
            .GetType()
            .GetMember(enumValue.ToString())
            .First()
            .GetCustomAttribute<DisplayAttribute>()
            .GetName();
    }

"Kulturabhängiger" Weg:

    public static string GetDisplayName(this Enum enumValue, CultureInfo ci)
    {
        var displayAttr = enumValue
            .GetType()
            .GetMember(enumValue.ToString())
            .First()
            .GetCustomAttribute<DisplayAttribute>();

        var resMan = displayAttr.ResourceType?.GetProperty(@"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager;

        return resMan?.GetString(displayAttr.Name, ci) ?? displayAttr.GetName();
    }
Pavel
quelle
1

2020 Update: Eine aktualisierte Version der Funktion, die von vielen in diesem Thread bereitgestellt wird, jetzt jedoch für C # 7.3:

Jetzt können Sie generische Methoden auf Aufzählungstypen beschränken, sodass Sie eine einzelne Methodenerweiterung schreiben können, um sie mit all Ihren Aufzählungen wie folgt zu verwenden:

Die generische Erweiterungsmethode:

public static string ATexto<T>(this T enumeración) where T : struct, Enum {
    var tipo = enumeración.GetType();
    return tipo.GetMember(enumeración.ToString())
    .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo).First()
    .GetCustomAttribute<DisplayAttribute>()?.Name ?? enumeración.ToString();
} 

Die Aufzählung:

public enum TipoImpuesto { 
IVA, INC, [Display(Name = "IVA e INC")]IVAeINC, [Display(Name = "No aplica")]NoAplica };

Wie man es benutzt:

var tipoImpuesto = TipoImpuesto.IVAeINC;
var textoTipoImpuesto = tipoImpuesto.ATexto(); // Prints "IVA e INC".

Bonus, Aufzählungen mit Flags: Wenn Sie mit normalen Aufzählungen arbeiten, reicht die obige Funktion aus. Wenn jedoch eine Ihrer Aufzählungen mit Flags mehrere Werte annehmen kann, müssen Sie sie wie folgt ändern (Dieser Code verwendet C # 8) Eigenschaften):

    public static string ATexto<T>(this T enumeración) where T : struct, Enum {

        var tipo = enumeración.GetType();
        var textoDirecto = enumeración.ToString();

        string obtenerTexto(string textoDirecto) => tipo.GetMember(textoDirecto)
            .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo)
            .First().GetCustomAttribute<DisplayAttribute>()?.Name ?? textoDirecto;

        if (textoDirecto.Contains(", ")) {

            var texto = new StringBuilder();
            foreach (var textoDirectoAux in textoDirecto.Split(", ")) {
                texto.Append($"{obtenerTexto(textoDirectoAux)}, ");
            }
            return texto.ToString()[0..^2];

        } else {
            return obtenerTexto(textoDirecto);
        }

    } 

Die Aufzählung mit Flaggen:

[Flags] public enum TipoContribuyente {
    [Display(Name = "Común")] Común = 1, 
    [Display(Name = "Gran Contribuyente")] GranContribuyente = 2, 
    Autorretenedor = 4, 
    [Display(Name = "Retenedor de IVA")] RetenedorIVA = 8, 
    [Display(Name = "Régimen Simple")] RégimenSimple = 16 } 

Wie man es benutzt:

var tipoContribuyente = TipoContribuyente.RetenedorIVA | TipoContribuyente.GranContribuyente;
var textoAux = tipoContribuyente.ATexto(); // Prints "Gran Contribuyente, Retenedor de IVA".
David
quelle
0

Basierend auf früheren Antworten habe ich diesen komfortablen Helfer erstellt, um alle DisplayAttribute-Eigenschaften lesbar zu unterstützen:

public static class EnumExtensions
    {
        public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue)
        {
            var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>();

            return new DisplayAttributeValues(enumValue, displayAttribute);
        }

        public sealed class DisplayAttributeValues
        {
            private readonly Enum enumValue;
            private readonly DisplayAttribute displayAttribute;

            public DisplayAttributeValues(Enum enumValue, DisplayAttribute displayAttribute)
            {
                this.enumValue = enumValue;
                this.displayAttribute = displayAttribute;
            }

            public bool? AutoGenerateField => this.displayAttribute?.GetAutoGenerateField();
            public bool? AutoGenerateFilter => this.displayAttribute?.GetAutoGenerateFilter();
            public int? Order => this.displayAttribute?.GetOrder();
            public string Description => this.displayAttribute != null ? this.displayAttribute.GetDescription() : string.Empty;
            public string GroupName => this.displayAttribute != null ? this.displayAttribute.GetGroupName() : string.Empty;
            public string Name => this.displayAttribute != null ? this.displayAttribute.GetName() : this.enumValue.ToString();
            public string Prompt => this.displayAttribute != null ? this.displayAttribute.GetPrompt() : string.Empty;
            public string ShortName => this.displayAttribute != null ? this.displayAttribute.GetShortName() : this.enumValue.ToString();
        }
    }
Kryszal
quelle
0

Ich habe versucht, dies als Bearbeitung zu tun, aber es wurde abgelehnt. Ich kann nicht verstehen warum.

Das Obige löst eine Ausnahme aus, wenn Sie es mit einer Aufzählung aufrufen, die eine Mischung aus benutzerdefinierten Attributen und einfachen Elementen enthält, z

public enum CommentType
{
    All = 1,
    Rent = 2,
    Insurance = 3,
    [Display(Name="Service Charge")]
    ServiceCharge = 4
}

Daher habe ich den Code geringfügig geändert, um vor dem Zugriff auf benutzerdefinierte Attribute zu suchen und den Namen zu verwenden, wenn keine gefunden werden.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes.Any() && descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}
rot
quelle
0

Mit MVC5 können Sie Folgendes verwenden:

public enum UserPromotion
{
   None = 0x0,

   [Display(Name = "Send Job Offers By Mail")]
   SendJobOffersByMail = 0x1,

   [Display(Name = "Send Job Offers By Sms")]
   SendJobOffersBySms = 0x2,

   [Display(Name = "Send Other Stuff By Sms")]
   SendPromotionalBySms = 0x4,

   [Display(Name = "Send Other Stuff By Mail")]
   SendPromotionalByMail = 0x8
}

Wenn Sie dann eine Dropdown-Auswahl erstellen möchten, können Sie Folgendes verwenden:

@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select") 
M. Hazara
quelle