Comment obtenir l'attribut de nom d'affichage d'un membre Enum via le code de rasoir MVC?

211

J'ai une propriété dans mon modèle appelée "Promotion" dont le type est une énumération d'indicateurs appelée "UserPromotion". Les membres de mon énumération ont des attributs d'affichage définis comme suit:

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

Maintenant, je veux pouvoir créer disons un ul dans ma vue pour montrer les valeurs sélectionnées de ma propriété "Promotion". C'est ce que j'ai fait jusqu'à présent, mais le problème est que comment puis-je obtenir les noms d'affichage ici?

<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
la source
12
MVC5 prend en charge l'attribut DisplayName sur les énumérations.
Bart Calixto
10
Pour être plus clair: seulement System.ComponentModel.DataAnnotations.DisplayAttribute. Non System.ComponentModel.DisplayNameAttribute.
kamranicus
1
Est-ce que cela inclut l'utilisation de la réflexion et donc un impact sur la performance? Parce que ça va s'appeler BEAUCOUP de temps.
Nico

Réponses:

182

METTRE À JOUR

La première solution était axée sur l'obtention des noms d'affichage à partir d'énumération. Le code ci-dessous devrait être la solution exacte à votre problème.

Vous pouvez utiliser cette classe d'assistance pour les énumérations:

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

Et puis vous pouvez l'utiliser dans votre vue comme suit:

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

J'espère que ça aide! :)

Hrvoje Stanisic
la source
8
Toutes les réponses utilisent .ToString, mais à partir de stackoverflow.com/q/483794/179311 , il est dit d'utiliser à la Enum.GetNameplace.
bradlis7
value.GetType (). GetField (value.ToString ()) était exactement ce que je cherchais!
cdie
Cette réponse est correcte avec une vérification nulle supplémentaire, mais si vous n'utilisez pas dotfuscation, la réponse sur stackoverflow.com/a/4412730/852806 semble plus simple.
HockeyJ
5
En GetDisplayValuevous devez d' abord tester descriptionAttributes == nullavant d'essayer d'accéder au tableau: descriptionAttributes[0]. Sinon, vous pouvez déclencher une exception et la ligne ci-dessous où vous vérifiez la valeur null ne sera jamais vraie.
Robert S.
Je suggérerais des changements mineurs: public IList statique <T> GetValues ​​(valeur Enum) pourrait être public statique IList <T> GetValues ​​(valeur T). EnumHelper <T> à => classe statique publique EnumHelper <T> où T: struct, IConvertible. Peut-être un constructeur statique? static EnumHelper () {if (! typeof (T) .IsEnum) {throw new ArgumentException ("T doit être un type énuméré"); }}
Tom
172

One liner - Syntaxe fluide

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

Exemple

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

Production

De quelle saison s'agit-il?
C'est l'été

Aydin
la source
2
N'existe pas une définition de GetCustomAttribute
Tito
3
@Tito assurez-vous que votre projet cible .NET Framework 4.5et que vous incluez les espaces de noms suivantsSystem.Net System.ComponentModel.DataAnnotations
Aydin
8
using System.Reflection; using System.ComponentModel.DataAnnotations; J'avais besoin de moi.
Sinned Lolwut
1
quelle terrible convention de dénomination!
curiousBoy
@curiousBoy Comment est GetAttribute<TAttribute>une terrible convention de dénomination? Il récupère l'attribut que vous spécifiez et utilise la casse pascal comme toutes les méthodes publiques.
Aydin
137

S'appuyant sur la grande réponse d'Aydin , voici une méthode d'extension qui ne nécessite aucun paramètre de type.

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

REMARQUE: GetName () doit être utilisé à la place de la propriété Name. Cela garantit que la chaîne localisée sera renvoyée si vous utilisez la propriété d'attribut ResourceType.

Exemple

Pour l'utiliser, il vous suffit de référencer la valeur d'énumération dans votre vue.

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

Production

Promotion: envoyer des offres d'emploi par courrier

Todd
la source
4
Assurez-vous d'ajouter les espaces de noms suivants: using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection;
Peter Kerr
Solution simple, mais j'obtiens {"Les modèles peuvent être utilisés uniquement avec un accès aux champs, un accès aux propriétés, un index de tableau à une dimension ou des expressions d'indexeur personnalisé à paramètre unique."}
Casey Crookston
En regardant d'autres réponses SO pour ce message d'erreur (je ne le connais pas), il semble que vous utilisiez cela à partir d'une méthode d'assistance Html (comme @Html.DisplayFor(m => m.myEnum.GetDisplayName()), qui ne fonctionnera pas, car ils s'attendent à ce que l'expression évaluée produise une propriété ou quelque chose de similaire. Vous devriez utiliser la valeur d'énumération nue comme dans l'exemple ci-dessus.
Todd
7
J'ai ajouté une vérification de référence nulle au résultat GetCustomAttribute<DisplayAttribute>()parce que pour certains énumérations, cela n'est peut-être pas présent. Il revient à enumValue.ToString()si le DisplayAttribute n'était pas présent.
H Dog
1
J'ai utilisé cela pour créer un List<SelectListItem>qui était rempli par un Enum avec toutes les DisplayAttribute.Nameannotations individuelles - cela a parfaitement fonctionné, merci !! 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

Sur la base de la réponse d'Aydin, je suggérerais une implémentation moins "duplicative" (car nous pourrions facilement obtenir Typela Enumvaleur elle-même, au lieu de la fournir comme paramètre 😉:

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

EDIT (basé sur le commentaire de @Vahagn Nahapetyan)

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

Maintenant, nous pouvons l'utiliser très propre de cette façon:

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

Ce qui se traduit par

"Le rêve"

Bernoulli IT
la source
1
De loin la réponse la plus simple et la plus simple. Merci!
Casey Crookston
Vous devez être prudent avec .First (). Cela lèvera une exception par exemple si votre nom d'énumération est "Equals"
Vahagn Nahapetyan
Je comprends le "danger" avec First (). Dans ce cas particulier, cela ne semble pas être un problème. Parce que c'est une méthode d'extension où thisdoit être une valeur Enum valide (et non nulle). Sinon, appeler la méthode lancerait déjà (ce qui est une responsabilité du code appelant). Cela fait que cela GetType()fournira à coup sûr le type d'énumération correct dans lequel enumvaluesera certainement membre. Mais GetCustomAttribute peut renvoyer une valeur nulle, j'ai donc fourni une version non exceptionnelle de la méthode pour renvoyer null lorsque la chaîne d'appels de méthode a une valeur de retour nulle quelque part. Merci!
Bernoulli IT
1
Pour la deuxième variante de votre code, il semble qu'il n'y ait pas besoin d'utiliser l'opérateur conditionnel nul après GetMember car cette méthode retourne toujours un tableau de MemberInfo et ne retourne jamais null. Et pour moi, il semble qu'il est préférable d'utiliser FirstOrDefault au lieu de simplement First. Ensuite, l'utilisation de l'opérateur à condition nulle après FirstOrDefault sera considérée comme cohérente.
Alex34758
28

Si vous utilisez MVC 5.1 ou supérieur, il existe un moyen plus simple et plus clair: utilisez simplement l'annotation des données (à partir de l' System.ComponentModel.DataAnnotationsespace de noms) comme ci-dessous:

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

Et en vue, mettez-le dans le bon assistant html:

@Html.EnumDropDownListFor(model => model.Color)
1_bug
la source
@SegmentationFault pourquoi? Pouvez-vous décrire votre problème? Quelle version de .NET / MVC utilisez-vous? Quelle erreur avez-vous? Veuillez être plus précis.
1_bug
6
Parce que cela ne fonctionne que pour Dropdowns, pas ailleurs.
Erreur de segmentation du
2
Ne semble pas exister dans le noyau .net
Lonefish
3
Le noyau .net utilise Html.GetEnumSelectList (typeof (YourEnum)) @Lonefish
Patrick Mcvay
2
si nous voulons utiliser @ Html.DisplayFor (yourEnumField), nous pouvons mettre un Enum.cshtml dans le répertoire DisplayTemplates (dans le répertoire partagé). dans ce fichier, nous devons mettre seulement 2 lignes. le premier est: "@model Enum" le second est: "@GetDisplayName (Model)". la méthode GetDisplayName doit être comme dans @Bernoulli IT answare
Développeur
11

Vous pouvez utiliser la méthode Type.GetMember , puis obtenir les informations d'attribut à l' aide de la réflexion:

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

Il y avait quelques articles similaires ici:

Obtenir des attributs de la valeur d'Enum

Comment faire pour que MVC3 DisplayFor affiche la valeur d'un attribut d'affichage Enum?

maximpa
la source
8

S'appuyant sur la grande réponse de Todd qui s'appuyait sur la grande réponse d' Aydin , voici une méthode d'extension générique qui ne nécessite aucun paramètre de type.

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

J'en avais besoin pour mon projet parce que quelque chose comme le code ci-dessous, où tous les membres de l'énumération DisplayAttributen'en ont pas, ne fonctionne pas avec la solution de Todd:

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

S'il s'agit d'une solution compliquée à un problème simple, faites-le moi savoir, mais c'est le correctif que j'ai utilisé.

Sinjai
la source
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
la source
Ne fonctionne pas: / Je reçois une erreurInvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Muflix
6

J'ai deux solutions pour cette question.

  1. La première solution consiste à obtenir les noms d'affichage à partir d'énumération.
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. La deuxième solution consiste à obtenir le nom d'affichage à partir du nom enum, mais qui sera divisé enum dans le langage de développeur, il est appelé patch.
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 Sunni
la source
5

Pour ASP.Net Core 3.0, cela a fonctionné pour moi (crédit aux répondeurs précédents).

Ma classe Enum:

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

Ma classe de modèles d'affichage:

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

Un exemple d'une vue de rasoir affichant une étiquette et une liste déroulante. Notez que la liste déroulante ne nécessite pas de méthode d'assistance:

@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>
}
Mer océan
la source
J'ajouterais une vérification sur la chaîne de retour de la méthode GetDisplayName. IsNullOrEmpty (retVal)? enumValue.ToString (): retVal;
Sniipe
4

Vous devez utiliser un peu de réflexion pour accéder à cet attribut:

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;

Je recommande d'encapsuler cette méthode dans une méthode d'extension ou de l'exécuter dans un modèle de vue.

alexn
la source
4

Avec Core 2.1,

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

combiner tous les cas de bord ensemble par le haut:

  • énumérer les membres avec les noms des membres de l'objet de base ( Equals, ToString)
  • Displayattribut facultatif

voici mon 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
la source
Belle solution qui gère l'attribut d'affichage facultatif. Merci!
Wellspring
3

Je suis désolé de le faire, mais je n'ai pu utiliser aucune des autres réponses telles quelles et je n'ai pas eu le temps d'en parler dans les commentaires.

Utilise la syntaxe C # 6.

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
la source
2

S'appuyant sur les réponses d'Aydin et Todd, voici une méthode d'extension qui vous permet également d'obtenir le nom à partir d'un fichier de ressources

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

et l'utiliser comme

public enum Season 
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}
Peter Kerr
la source
J'essaie de faire fonctionner cela pour mon projet mais j'obtiens une erreur avec le "nouveau ResourceManager (ressource) .GetString (nom);" ligne. J'avais posé une question ( stackoverflow.com/questions/31319251/… ) et on m'a envoyé ici. Lorsque je consulte le "ResourceManager (ressource)" lors de son exécution, il renvoie "Resources.Enums.resource". Toute aide serait grandement appréciée. Je vous remercie!
Karinne
Mise à jour du code pour mieux gérer les valeurs nulles lorsque aucun nom d'affichage n'est défini pour certaines des valeurs d'énumération - cela pourrait aider
Peter Kerr
Cela ne fonctionnait toujours pas. J'ai mis à jour ma question sur stackoverflow.com/questions/31319251/… avec le message d'erreur. Merci pour l'aide!
Karinne
1

Je souhaite contribuer avec l'extension d'énumération GetDisplayName dépendante de la culture. J'espère que cela sera utile pour quiconque googler cette réponse comme moi précédemment:

façon "standard" comme Aydin Adn et Todd l'ont mentionné:

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

Méthode "dépendante de la culture":

    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
la source
1

Mise à jour 2020: une version mise à jour de la fonction fournie par beaucoup dans ce fil, mais maintenant pour C # 7.3 à partir de:

Vous pouvez maintenant restreindre les méthodes génériques aux types d'énumérations afin que vous puissiez écrire une seule extension de méthode pour l'utiliser avec toutes vos énumérations comme ceci:

La méthode d'extension générique:

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

L'énumération:

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

Comment l'utiliser:

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

Bonus, énumérations avec indicateurs: si vous avez affaire à des énumérations normales, la fonction ci-dessus est suffisante, mais si l'une de vos énumérations peut prendre plusieurs valeurs avec l'utilisation d'indicateurs, vous devrez la modifier comme ceci (ce code utilise C # 8 fonctionnalités):

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

    } 

L'énumération avec des drapeaux:

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

Comment l'utiliser:

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

Sur la base des réponses précédentes, j'ai créé cette aide confortable pour prendre en charge toutes les propriétés DisplayAttribute d'une manière lisible:

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
la source
0

J'ai essayé de faire cela comme un montage mais cela a été rejeté; Je ne vois pas pourquoi.

Ce qui précède lèvera une exception si vous l'appelez avec un Enum qui a un mélange d'attributs personnalisés et d'éléments simples, par exemple

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

J'ai donc légèrement modifié le code pour vérifier les attributs personnalisés avant d'essayer d'y accéder et d'utiliser le nom s'il n'en trouve aucun.

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();
    }
}
rouge
la source
0

En utilisant MVC5, vous pouvez utiliser:

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
}

alors si vous voulez créer un sélecteur déroulant, vous pouvez utiliser:

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