MVCかみそりコードを介してEnumメンバーの表示名属性を取得する方法


211

モデルに「Promotion」というプロパティがあります。そのタイプは「UserPromotion」というフラグ列挙型です。私の列挙型のメンバーには、次のように設定された表示属性があります。

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

ここで、「Promotion」プロパティの選択された値を表示するために、ビューにulを作成できるようにしたいと思います。これは私がこれまでに行ったことですが、問題はどのようにしてここで表示名を取得できるかということです。

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

12
MVC5は列挙型のDisplayName属性をサポートします。
Bart Calixto 2014

10
より明確にするために:のみSystem.ComponentModel.DataAnnotations.DisplayAttribute。ないSystem.ComponentModel.DisplayNameAttribute
kamranicus

1
これにはリフレクションの使用が含まれるため、パフォーマンスに影響しますか?これは長い時間と呼ばれます。
ニコ

回答:


182

更新

最初のソリューションは、列挙型から表示名を取得することに焦点を当てていました。以下のコードは、問題の正確な解決策です。

このヘルパークラスを列挙型に使用できます。

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

そして、あなたはそれをあなたの見解で次のように使うことができます:

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

それが役に立てば幸い!:)


8
すべての回答はを使用しています.ToStringが、stackoverflow.com/q/483794/179311から、Enum.GetName代わりに使用するように指示されています。
bradlis7 2014

value.GetType()。GetField(value.ToString())はまさに私が探していたものです!
2016年

この回答は、いくつかの追加されたnullチェックで問題ありませんが、dotfuscationを使用していない場合、stackoverflow.com / a / 4412730/852806での回答はより単純に見えます。
HockeyJ 2017

5
では、配列にアクセスする前にGetDisplayValueまずテストdescriptionAttributes == nullする必要がありますdescriptionAttributes[0]。そうしないと、例外が発生する可能性があり、nullをチェックする以下の行はtrueになりません。
ロバートS.

マイナーな変更を提案します。パブリック静的IList <T> GetValues(Enum value)はパブリック静的IList <T> GetValues(T value)になる可能性があります。EnumHelper <T> to => public static class EnumHelper <T>ここで、T:構造体、IConvertible。たぶん静的なコンストラクタ?static EnumHelper(){if(!typeof(T).IsEnum){throw new ArgumentException( "T must be a enumulated type"); }}
トム

172

ワンライナー-流暢な構文

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

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

出力

今の季節は?
夏です


2
GetCustomAttributeの定義が存在しない
Tito

3
@Titoは、プロジェクトがターゲット.NET Framework 4.5であること、および次の名前空間が含まれていることを確認しますSystem.Net System.ComponentModel.DataAnnotations
Aydin

8
System.Reflectionを使用します。System.ComponentModel.DataAnnotationsを使用します。私に必要でした。
Sinned Lolwut

1
なんとひどい命名規則か!
curiousBoy 2019

@curiousBoy GetAttribute<TAttribute>ひどい命名規則はどうですか?すべてのパブリックメソッドと同様に、指定した属性を取得し、パスカルケーシングを使用します。
アイディン、

137

アイディンのすばらしい答えに基づいて、型パラメーターを必要としない拡張メソッドを次に示します。

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

注:GetName()は、Nameプロパティの代わりに使用する必要があります。これにより、ResourceType属性プロパティを使用する場合、ローカライズされた文字列が確実に返されます。

これを使用するには、ビューで列挙値を参照するだけです。

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

出力

プロモーション:メールで求人を送信


4
次の名前空間を必ず追加してください。System.ComponentModel.DataAnnotationsを使用します。System.Linqを使用します。System.Reflectionを使用します。
Peter Kerr

洗練されたソリューションですが、{「テンプレートは、フィールドアクセス、プロパティアクセス、1次元配列インデックス、または単一パラメーターのカスタムインデクサー式でのみ使用できます。」}
Casey Crookston

このエラーメッセージに対する他のSOの回答(私はそれに慣れていない)を見ると、Htmlヘルパーメソッド(@Html.DisplayFor(m => m.myEnum.GetDisplayName())これは、評価された式がプロパティを生成することを期待しているため機能しないなど)からこれを使用している可能性があります上記の例のように裸の列挙値を使用する必要があります
Todd

7
GetCustomAttribute<DisplayAttribute>()一部の列挙型ではこれが存在しない可能性があるため、結果にnull参照チェックを追加しました。enumValue.ToString()DisplayAttributeが存在しなかった場合にフォールバックします。
Hドッグ

1
私はこれを使用しList<SelectListItem>て、Enumによってすべての個別のDisplayAttribute.Nameアノテーションが入力されたを作成しました-これは完全に機能しました、ありがとうございます!! 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() }); }
ホッパー

61

アイディンの答えに基づいて、あまり「重複しない」実装を提案します(パラメーターとして提供する代わりにTypeEnum値自体からを簡単に取得できるためです😉:

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

編集(@Vahagn Nahapetyanのコメントに基づく)

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

これで、次のように非常にクリーンに使用できます。

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

その結果

"夢"


1
すべての答えの中ではるかに単純で最も簡単です。ありがとう!
Casey Crookston、2017年

.First()には注意が必要です。これは、たとえば、列挙名が「等しい」の場合、例外をスローします
Vahagn Nahapetyan

First()の「危険」を理解しています。この特定のケースではそれは問題に見えません。これは、this有効な(nullではない)Enum値でなければならない拡張メソッドであるためです。それ以外の場合、メソッドを呼び出すと、既にスローされます(これは呼び出しコードの責任です)。これにより、確実にメンバーとなるGetType()正しい列挙型が確実に提供されますenumvalue。しかし、GetCustomAttributeはnull値を返す可能性があるため、メソッド呼び出しのチェーンにnullの戻り値がどこかにある場合にnullを返すために、例外ではないバージョンのメソッドを提供しました。ありがとう!
ベルヌーイIT

1
コードの2番目のバリアントの場合、このメソッドは常にMemberInfoの配列を返し、nullを返さないため、GetMemberの後にnull条件演算子を使用する必要がないようです。そして、私にとっては、FirstだけではなくFirstOrDefaultを使用する方が良いようです。次に、FirstOrDefaultの後にnull条件演算子を使用すると、一貫性があることがわかります。
Alex34758

28

MVC 5.1以降を使用している場合は、よりシンプルで明確な方法がありSystem.ComponentModel.DataAnnotationsます。以下のように(名前空間からの)データ注釈を使用するだけです。

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

そして、ビューでは、それを適切なhtmlヘルパーに入れます:

@Html.EnumDropDownListFor(model => model.Color)

@SegmentationFaultなんで?あなたの問題を説明できますか?どのバージョンの.NET / MVCを使用していますか?どのようなエラーが発生しましたか?より具体的にしてください。
1_bug 2016

6
ドロップダウンでのみ機能し、他では機能しないためです。
セグメンテーションフォールト2016

2
.netコアには存在しないようです
Lonefish '19年

3
.netコアはHtml.GetEnumSelectList(typeof(YourEnum))@Lonefishを使用
Patrick Mcvay 2017年

2
@ Html.DisplayFor(yourEnumField)を使用する場合は、Enum.cshtmlをDisplayTemplatesディレクトリ(共有ディレクトリ内)に配置できます。このファイルには、2行だけを入力する必要があります。1つ目は「@model Enum」、2つ目は「@GetDisplayName(Model)」です。GetDisplayNameメソッドは@Bernoulli IT answareのようにする必要があります
開発者

11

あなたは使用することができType.GetMember方法を、次に、属性情報を取得するリフレクションを使用しました:

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

ここにいくつかの同様の投稿がありました:

Enumの値の属性を取得する

列挙型のDisplay-Attributeの値をMVC3 DisplayForに表示させる方法は?


8

アイディンの素晴らしい答えに基づいたトッドの素晴らしい答えに基づいて、型パラメーターを必要としない汎用的な拡張メソッドを次に示します。

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

列挙型のすべてのメンバーがを持っているDisplayAttributeわけではない以下のコードのようなものが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

これが単純な問題の複雑な解決策である場合は、お知らせください。ただし、これは私が使用した修正でした。


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>

動作しません:/エラーが発生しますInvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Muflix

6

この質問には2つの解決策があります。

  1. 最初の解決策は、列挙型から表示名を取得することです。
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. 2番目の解決策は、列挙名から表示名を取得することですが、それはパッチと呼ばれる開発者言語で列挙型分割されます。
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>

5

ASP.Net Core 3.0の場合、これは私のために機能しました(以前の回答者への信用)。

私の列挙クラス:

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

私のビューモデルクラス:

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

ラベルとドロップダウンリストを表示するかみそりビューの例。ドロップダウンリストにはヘルパーメソッドは必要ありません。

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

GetDisplayNameメソッドの戻り文字列にチェックを追加します。IsNullOrEmpty(retVal)?enumValue.ToString():retVal;
スナイペ

4

その属性にアクセスするために、少しリフレクションを使用する必要があります。

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;

このメソッドを拡張メソッドでラップするか、ビューモデルで実行することをお勧めします。


4

Core 2.1では、

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

4

上からすべてのエッジケースを組み合わせる:

  • 基本オブジェクトメンバーの名前を持つ列挙型メンバー(EqualsToString
  • オプションDisplay属性

これが私のコードです:

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

オプションのDisplay属性を処理する優れたソリューション。ありがとう!
Wellspring

3

申し訳ありませんが、他の回答をそのまま使用することはできず、コメントで公開する時間もありませんでした。

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

2

アイディンとトッドの答えにさらに基づいて、リソースファイルから名前を取得することもできる拡張メソッドを次に示します

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

そしてそれを

public enum Season 
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}

私のプロジェクトでこれを機能させようとしていますが、 "new ResourceManager(resource).GetString(name);"でエラーが発生します。ライン。私は質問をした(stackoverflow.com/questions/31319251/…)と私はここに送られました。実行中に「ResourceManager(resource)」を表示すると、「Resources.Enums.resource」が返されます。どんな助けでも大歓迎です。ありがとうございました!
Karinne

一部の列挙値に表示名が設定されていない場合にnullをより適切に処理するようにコードを更新しました-役立つかもしれません
Peter Kerr

それでもうまくいきませんでした。私はstackoverflow.com/questions/31319251/…の質問をエラーメッセージで更新しました。助けてくれてありがとう!
Karinne

1

カルチャーに依存するGetDisplayName列挙型拡張機能で貢献したいと思います。これが私のようにこの答えをグーグルする誰にとっても役立つことを願っています:

Aydin AdnToddが述べた「標準」の方法:

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

「文化に依存する」方法:

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

1

2020 Update:このスレッドで多くの人が提供していた関数の更新バージョンですが、現在はC#7.3以降に対応しています。

これで、ジェネリックメソッドを列挙型に制限できるため、次のようにすべての列挙型で使用する単一のメソッド拡張を記述できます。

一般的な拡張メソッド:

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

列挙型:

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

どうやって使うのですか:

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

ボーナス、フラグ付き列挙型通常の列挙型を処理している場合は、上記の関数で十分ですが、フラグを使用して列挙型のいずれかが複数の値を取得できる場合は、このように変更する必要があります(このコードはC#8を使用します)特徴):

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

    } 

フラグ付きの列挙型:

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

どうやって使うのですか:

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

0

以前の回答に基づいて、すべてのDisplayAttributeプロパティを読み取り可能な方法でサポートするために、この快適なヘルパーを作成しました。

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

0

これを編集として試みましたが、拒否されました。理由がわかりません。

上記は、カスタム属性とプレーンアイテムが混在するEnumで呼び出すと例外がスローされます。例:

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

そこで、コードを少し変更して、カスタム属性にアクセスする前にそれらをチェックし、見つからない場合は名前を使用するようにしました。

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

0

MVC5を使用すると、以下を使用できます。

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
}

次に、ドロップダウンセレクターを作成する場合は、次を使用できます。

@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select") 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.