Bagaimana cara mendapatkan Atribut Nama Tampilan anggota Enum melalui kode pisau cukur MVC?

211

Saya mendapatkan properti dalam model saya yang disebut "Promosi" yang tipenya adalah flag enum yang disebut "UserPromotion". Anggota enum saya memiliki atribut tampilan yang ditetapkan sebagai berikut:

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

Sekarang saya ingin dapat membuat say ul dalam pandangan saya untuk menunjukkan nilai yang dipilih dari properti "Promosi" saya. Inilah yang telah saya lakukan sejauh ini tetapi masalahnya adalah bagaimana saya bisa mendapatkan nama tampilan di sini?

<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
sumber
12
MVC5 mendukung atribut DisplayName pada enum.
Bart Calixto
10
Untuk lebih jelas: Hanya System.ComponentModel.DataAnnotations.DisplayAttribute. Tidak System.ComponentModel.DisplayNameAttribute.
kamranicus
1
Apakah ini termasuk penggunaan refleksi dan karenanya berdampak pada kinerja? Karena ini akan disebut BANYAK waktu.
Nico

Jawaban:

182

MEMPERBARUI

Solusi pertama difokuskan pada mendapatkan nama tampilan dari enum. Kode di bawah ini harus menjadi solusi tepat untuk masalah Anda.

Anda bisa menggunakan kelas penolong ini untuk enum:

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

Dan kemudian Anda dapat menggunakannya dalam tampilan Anda sebagai berikut:

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

Semoga ini bisa membantu! :)

Hrvoje Stanisic
sumber
8
Semua jawaban digunakan .ToString, tetapi dari stackoverflow.com/q/483794/179311 , ia mengatakan untuk menggunakannya Enum.GetNamesebagai gantinya.
bradlis7
value.GetType (). GetField (value.ToString ()) persis seperti yang saya cari!
cdie
Jawaban ini baik-baik saja dengan menambahkan beberapa pemeriksaan nol, tetapi jika Anda tidak menggunakan dotfuscation jawabannya di stackoverflow.com/a/4412730/852806 tampaknya lebih sederhana.
Hoki
5
Dalam GetDisplayValueAnda harus tes pertama descriptionAttributes == nullsebelum Anda mencoba untuk mengakses array: descriptionAttributes[0]. Kalau tidak, Anda dapat mengajukan pengecualian dan baris di bawah tempat Anda memeriksa null tidak akan pernah benar.
Robert S.
Saya akan menyarankan perubahan di bawah umur: IList statis publik <T> GetValues ​​(nilai Enum) bisa menjadi IList statis publik <T> GetValues ​​(nilai T). EnumHelper <T> ke => kelas statis publik EnumHelper <T> di mana T: struct, IConvertible. Mungkin konstruktor statis? static EnumHelper () {if (! typeof (T) .IsEnum) {throw new ArgumentException ("T harus tipe enumerated"); }}
Tom
172

One liner - Sintaks fasih

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

Contoh

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

Keluaran

Musim apa itu?
Ini musim panas

Aydin
sumber
2
Tidak ada definisi GetCustomAttribute
Tito
3
@Tito memastikan bahwa proyek Anda menargetkan .NET Framework 4.5dan bahwa Anda termasuk ruang nama berikutSystem.Net System.ComponentModel.DataAnnotations
Aydin
8
menggunakan System.Reflection; menggunakan System.ComponentModel.DataAnnotations; Dibutuhkan untukku.
Sinned Lolwut
1
konvensi penamaan yang mengerikan!
curiousBoy
@curiousBoy Bagaimana GetAttribute<TAttribute>konvensi penamaan yang mengerikan? Itu mengambil atribut yang Anda tentukan dan menggunakan casing pascal seperti semua metode publik seharusnya.
Aydin
137

Membangun jawaban Aydin yang luar biasa , inilah metode ekstensi yang tidak memerlukan parameter tipe apa pun.

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

CATATAN: GetName () harus digunakan sebagai ganti properti Name. Ini memastikan bahwa string yang dilokalkan akan dikembalikan jika menggunakan properti atribut ResourceType.

Contoh

Untuk menggunakannya, cukup referensi nilai enum di tampilan Anda.

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

Keluaran

Promosi: Kirim Penawaran Pekerjaan Melalui Surat

Todd
sumber
4
Selain dapat menambahkan ruang nama berikut: using System; menggunakan System.ComponentModel.DataAnnotations; menggunakan System.Linq; menggunakan System.Reflection;
Peter Kerr
Solusi yang licin, tetapi saya mendapatkan {"Templat hanya dapat digunakan dengan akses bidang, akses properti, indeks array dimensi tunggal, atau ekspresi pengindeks kustom parameter tunggal."}
Casey Crookston
Melihat jawaban SO lainnya untuk pesan kesalahan ini (saya tidak terbiasa dengan itu), tampaknya Anda mungkin menggunakan ini dari dalam metode penolong Html (seperti @Html.DisplayFor(m => m.myEnum.GetDisplayName()), yang tidak akan berfungsi, karena mereka mengharapkan ekspresi yang dievaluasi menghasilkan sebuah properti atau sesuatu yang serupa. Anda harus menggunakan nilai bare enum seperti pada contoh di atas.
Todd
7
Saya menambahkan cek referensi nol ke hasil GetCustomAttribute<DisplayAttribute>()karena untuk beberapa Enums mungkin ini tidak ada. Itu kembali ke enumValue.ToString()jika DisplayAttribute tidak ada.
H Dog
1
Saya menggunakan ini untuk membuat List<SelectListItem>yang diisi oleh Enum dengan semua DisplayAttribute.Nameanotasi individu - ini bekerja dengan baik, terima kasih !! 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

Berdasarkan jawaban Aydin saya akan menyarankan implementasi yang kurang "duplikat" (karena kita bisa dengan mudah mendapatkan Typedari Enumnilai itu sendiri, daripada memberikannya sebagai parameter 😉:

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

EDIT (berdasarkan komentar @Vahagn Nahapetyan)

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

Sekarang kita dapat menggunakannya dengan sangat bersih dengan cara ini:

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

Yang mengakibatkan

"Mimpi"

Bernoulli
sumber
1
Sejauh ini jawaban yang paling sederhana dan termudah. Terima kasih!
Casey Crookston
Anda harus berhati-hati dengan .First (). Ini akan memberikan pengecualian misalnya jika nama enum Anda adalah "Setara"
Vahagn Nahapetyan
Saya mengerti "bahaya" dengan First (). Dalam kasus khusus ini sepertinya tidak menjadi masalah. Karena itu adalah metode ekstensi di mana thisharus nilai Enum yang valid (bukan nol). Kalau tidak memanggil metode akan sudah melempar (yang merupakan tanggung jawab kode panggilan). Ini membuat yang GetType()pasti akan memberikan Jenis Enum yang benar di mana enumvaluepasti akan menjadi anggota. Tetapi GetCustomAttribute mungkin mengembalikan nilai nol jadi saya memberikan versi metode yang tidak biasa untuk mengembalikan nol ketika rantai panggilan metode memiliki nilai balik nol di suatu tempat. Terima kasih!
Bernoulli IT
1
Untuk varian kedua kode Anda, sepertinya tidak perlu menggunakan operator bersyarat nol setelah GetMember karena metode ini selalu mengembalikan array MemberInfo dan tidak pernah mengembalikan nol. Dan bagi saya sepertinya lebih baik menggunakan FirstOrDefault daripada hanya First. Kemudian penggunaan operator kondisi-nol setelah FirstOrDefault akan terlihat konsisten.
Alex34758
28

Jika Anda menggunakan MVC 5.1 atau lebih tinggi, ada cara yang lebih sederhana dan lebih jelas: cukup gunakan anotasi data (dari System.ComponentModel.DataAnnotationsnamespace) seperti di bawah ini:

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

Dan dalam pandangan, masukkan saja ke dalam bantuan html yang tepat:

@Html.EnumDropDownListFor(model => model.Color)
1_bug
sumber
@SegmentationFault mengapa? Bisakah Anda menggambarkan masalah Anda? Versi .NET / MVC mana yang Anda gunakan? Kesalahan apa yang Anda punya? Harap lebih spesifik.
1_bug
6
Karena ini hanya berfungsi untuk Dropdown, tidak di tempat lain.
Segmentasi Fault
2
Sepertinya tidak ada di .net core
Lonefish
3
.net core menggunakan Html.GetEnumSelectList (typeof (YourEnum)) @Lonefish
Patrick Mcvay
2
jika kita ingin menggunakan @ Html.DisplayFor (yourEnumField) kita dapat meletakkan Enum.cshtml di direktori DisplayTemplates (dalam direktori bersama). dalam file ini kita hanya perlu meletakkan 2 baris. yang pertama adalah: "@model Enum" yang kedua adalah: "@GetDisplayName (Model)." metode GetDisplayName harus seperti di @Bernoulli IT answare
Pengembang
11

Anda bisa menggunakan Metode Type.GetMember , lalu dapatkan info atribut menggunakan refleksi:

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

Ada beberapa posting serupa di sini:

Mendapatkan atribut nilai Enum

Bagaimana cara membuat MVC3 DisplayFor menunjukkan nilai atribut-tampilan Enum?

maksimpa
sumber
8

Membangun di atas jawaban hebat Todd yang dibangun di atas jawaban hebat Aydin , inilah metode ekstensi generik yang tidak memerlukan parameter tipe apa pun.

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

Saya membutuhkan ini untuk proyek saya karena sesuatu seperti kode di bawah ini, di mana tidak setiap anggota enum memiliki DisplayAttribute, tidak bekerja dengan solusi 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

Jika ini adalah solusi rumit untuk masalah sederhana, harap beri tahu saya, tetapi ini adalah perbaikan yang saya gunakan.

Sinjai
sumber
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
sumber
Tidak berfungsi: / Saya menerima pesan kesalahanInvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Muflix
6

Saya punya dua solusi untuk Pertanyaan ini.

  1. Solusi pertama adalah mendapatkan nama tampilan dari enum.
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. Solusi kedua adalah mendapatkan nama tampilan dari nama enum tapi itu akan dibagi menjadi bahasa pengembang itu disebut 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
sumber
5

Untuk ASP.Net Core 3.0, ini bekerja untuk saya (kredit untuk penjawab sebelumnya).

Kelas Enum saya:

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

Kelas Model Tampilan Saya:

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

Contoh tampilan pisau cukur yang menampilkan label dan daftar drop-down. Perhatikan bahwa daftar drop-down tidak memerlukan metode pembantu:

@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>
}
Sea_Ocean
sumber
Saya akan menambahkan tanda centang pada metode return string GetDisplayName.IsNullOrEmpty (retVal)? enumValue.ToString (): retVal;
Sniipe
4

Anda perlu menggunakan sedikit refleksi untuk mengakses atribut itu:

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;

Saya sarankan membungkus metode ini dalam metode ekstensi atau melakukan ini dalam model tampilan.

Alex
sumber
4

Dengan Core 2.1,

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

menggabungkan semua kasus tepi bersama-sama dari atas:

  • enum anggota dengan nama anggota objek dasar ( Equals,ToString )
  • Displayatribut opsional

ini kode saya:

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
sumber
Solusi bagus yang menangani atribut Display opsional. Terima kasih!
Mata air
3

Saya minta maaf untuk melakukan ini, tetapi saya tidak bisa menggunakan salah satu dari jawaban lain apa adanya dan tidak punya waktu untuk menyelesaikannya di komentar.

Menggunakan sintaks 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
sumber
2

Membangun lebih jauh jawaban Aydin dan Todd, berikut adalah metode ekstensi yang juga memungkinkan Anda mendapatkan nama dari file sumber daya

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

dan menggunakannya seperti

public enum Season 
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}
Peter Kerr
sumber
Saya mencoba agar ini berfungsi untuk proyek saya, tetapi saya mendapatkan kesalahan dengan "ResourceManager (sumber daya) baru. GetString (nama);" baris. Saya telah mengajukan pertanyaan ( stackoverflow.com/questions/31319251/… ) dan saya dikirim ke sini. Ketika saya melihat "ResourceManager (sumber daya)" saat menjalankannya mengembalikan "Resources.Enums.resource". Bantuan apa pun akan sangat dihargai. Terima kasih!
Karinne
Diperbarui kode untuk menangani nulls dengan lebih baik ketika Anda tidak memiliki Nama Tampilan yang ditetapkan untuk beberapa nilai enum - mungkin membantu
Peter Kerr
Itu masih tidak berhasil. Saya memperbarui pertanyaan saya di stackoverflow.com/questions/31319251/… dengan pesan kesalahan. Terima kasih untuk bantuannya!
Karinne
1

Saya ingin berkontribusi dengan ekstensi enum GetDisplayName yang bergantung pada budaya. Semoga ini bermanfaat bagi siapa pun yang menelusuri jawaban ini seperti saya sebelumnya:

"standar" seperti yang disebutkan oleh Aydin Adn dan Todd :

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

Cara "tergantung budaya":

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

Pembaruan 2020: Versi terbaru dari fungsi yang disediakan oleh banyak orang di utas ini tetapi sekarang untuk C # 7.3 dan seterusnya:

Sekarang Anda dapat membatasi metode generik ke enum jenis sehingga Anda dapat menulis ekstensi metode tunggal untuk menggunakannya dengan semua enum Anda seperti ini:

Metode ekstensi umum:

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

Enum:

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

Bagaimana cara menggunakannya:

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

Bonus, Enum dengan Bendera: Jika Anda berurusan dengan enum normal, fungsi di atas sudah cukup, tetapi jika salah satu enum Anda dapat mengambil beberapa nilai dengan menggunakan bendera maka Anda harus memodifikasinya seperti ini (Kode ini menggunakan C # 8 fitur):

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

    } 

Enum dengan bendera:

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

Bagaimana cara menggunakannya:

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

Berdasarkan jawaban sebelumnya saya telah membuat penolong yang nyaman ini untuk mendukung semua properti DisplayAttribute dengan cara yang dapat dibaca:

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

Saya mencoba melakukan ini sebagai suntingan tetapi ditolak; Saya tidak mengerti mengapa.

Di atas akan mengeluarkan pengecualian jika Anda menyebutnya dengan Enum yang memiliki campuran atribut khusus dan item biasa, mis

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

Jadi saya telah memodifikasi kode sedikit untuk memeriksa atribut khusus sebelum mencoba mengaksesnya, dan menggunakan namanya jika tidak ada yang ditemukan.

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

Menggunakan MVC5 Anda bisa menggunakan:

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
}

maka jika Anda ingin membuat pemilih dropdown Anda dapat menggunakan:

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