列挙型の値の属性を取得
-
22-09-2019 - |
質問
私は列挙型自体の列挙値とないの属性を取得することが可能であるかどうかを知りたいですか?例えば、私は、次の列挙型があるとします:
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
私は列挙型指定されたい何、列挙型の文字列値とその説明の2つのタプルを生成します。
の値は簡単だっます:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
しかし、どのように、私はTuple.Descを投入するために、description属性の値を得るのですか?属性は、列挙型自体に属している場合、私はそれを行う方法を考えることができますが、私は、列挙型の値からそれを取得する方法についての損失で午前ます。
解決
これはあなたが必要なものを行う必要があります。
var enumType = typeof(FunkyAttributesEnum);
var memberInfos = enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == enumType);
var valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)valueAttributes[0]).Description;
他のヒント
コードのこの作品は、あなたが一般的な属性を取得することができます任意の列挙型のちょっといい拡張メソッドを与える必要があります。私は少しそれを使用するように簡単ですので、それは上記のラムダ関数に違う信じて - あなただけのジェネリック型を渡す必要があります。
。public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (attributes.Length > 0) ? (T)attributes[0] : null;
}
}
これは選択のためのラムダを使用して一般的な実装である。
public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
where T : Attribute
{
T attribute =
enumeration
.GetType()
.GetMember(enumeration.ToString())
.Where(member => member.MemberType == MemberTypes.Field)
.FirstOrDefault()
.GetCustomAttributes(typeof(T), false)
.Cast<T>()
.SingleOrDefault();
if (attribute == null)
return default(Expected);
return expression(attribute);
}
このようにそれを呼び出します:
string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
私はもう少し拡張可能なソリューションを作成するために、ここでの回答のカップルをマージされました。私はそれが将来的には他の誰にも便利です念のためにそれを提供しています。オリジナルの投稿はこちらここhref="https://stackoverflow.com/a/19621436/1454806">
この解決策は、列挙に拡張メソッドのペアを作成します。最初はあなたの値に関連付けられた任意の属性を取得するためにリフレクションを使用することができます。第二の特異 例として、using System;
using System.ComponentModel;
public static class EnumExtensions {
// This extension method is broken out so you can use a similar pattern with
// other MetaData elements in the future. This is your base method for each.
public static T GetAttribute<T>(this Enum value) where T : Attribute {
var type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
return attributes.Length > 0
? (T)attributes[0]
: null;
}
// This method creates a specific call to the above method, requesting the
// Description MetaData attribute.
public static string ToName(this Enum value) {
var attribute = value.GetAttribute<DescriptionAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
}
DescriptionAttribute
戻ることのDescription
値取り出しを呼び出します。DescriptionAttribute
からSystem.ComponentModel
属性を使用することを検討してください。using System.ComponentModel;
public enum Days {
[Description("Sunday")]
Sun,
[Description("Monday")]
Mon,
[Description("Tuesday")]
Tue,
[Description("Wednesday")]
Wed,
[Description("Thursday")]
Thu,
[Description("Friday")]
Fri,
[Description("Saturday")]
Sat
}
は上記の拡張メソッドを使用するには、今、単純に次のことを呼ぶだろう
Console.WriteLine(Days.Mon.ToName());
または
var day = Days.Mon;
Console.WriteLine(day.ToName());
AdamCrawford応答のに加えて、私はさらにそれのフィードを取得することが、より専門的な拡張メソッドを作成しました説明ます。
public static string GetAttributeDescription(this Enum enumValue)
{
var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
return attribute == null ? String.Empty : attribute.Description;
}
ので説明を取得するには、次のいずれか
のように、元の拡張メソッドを使用することができますstring desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description
またはあなたは単にここで拡張メソッドを呼び出すことができます:
string desc = myEnumVariable.GetAttributeDescription();
うまくいけば、あなたのコードは少し読みやすくする必要があります。。
を流暢1ライナー... の
ここで私DisplayAttribute
とName
特性の両方が含まれているDescription
を使用しています。
public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
return enumType.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
}
<時間>
の例の
public enum ModesOfTransport
{
[Display(Name = "Driving", Description = "Driving a car")] Land,
[Display(Name = "Flying", Description = "Flying on a plane")] Air,
[Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
}
void Main()
{
ModesOfTransport TransportMode = ModesOfTransport.Sea;
DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
}
<時間>
出力
Name: Sea cruise
Description: Cruising on a dinghy
ここで表示属性から情報を取得するためのコードです。これは、属性を取得するために、一般的な方法を使用しています。属性が見つからない場合には、パスカル/キャメルケースと文字列に列挙値がタイトルケースに変換(コードはここにを得変換します>)
public static class EnumHelper
{
// Get the Name value of the Display attribute if the
// enum has one, otherwise use the value converted to title case.
public static string GetDisplayName<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
{
var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
}
// Get the ShortName value of the Display attribute if the
// enum has one, otherwise use the value converted to title case.
public static string GetDisplayShortName<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
{
var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
}
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="TEnum">The enum type</typeparam>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="value">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
private static T GetAttributeOfType<TEnum, T>(this TEnum value)
where TEnum : struct, IConvertible
where T : Attribute
{
return value.GetType()
.GetMember(value.ToString())
.First()
.GetCustomAttributes(false)
.OfType<T>()
.LastOrDefault();
}
}
これはタイトルケースに変換するための文字列の拡張メソッドです。
/// <summary>
/// Converts camel case or pascal case to separate words with title case
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ToSpacedTitleCase(this string s)
{
//https://stackoverflow.com/a/155486/150342
CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;
return textInfo
.ToTitleCase(Regex.Replace(s,
"([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
}
は列挙型から辞書を取得します。
public static IDictionary<string, int> ToDictionary(this Type enumType)
{
return Enum.GetValues(enumType)
.Cast<object>()
.ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k);
}
さて...
のように、これを呼び出しますvar dic = typeof(ActivityType).ToDictionary();
EnumDecriptionのExtメソッド
public static string ToEnumDescription(this Enum en) //ext method
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
return ((DescriptionAttribute)attrs[0]).Description;
}
return en.ToString();
}
public enum ActivityType
{
[Description("Drip Plan Email")]
DripPlanEmail = 1,
[Description("Modification")]
Modification = 2,
[Description("View")]
View = 3,
[Description("E-Alert Sent")]
EAlertSent = 4,
[Description("E-Alert View")]
EAlertView = 5
}
私は、列挙型の値から説明を取得するには、この拡張メソッドを実装しました。これは、列挙型のすべての種類のために働くます。
public static class EnumExtension
{
public static string ToDescription(this System.Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
}
ここで使用して、AdamCrawfordの答えの.NET Coreバージョンの System.Reflection.TypeExtensionsこちら;
public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (T)attributes?.ToArray()[0];
}
}
ネットフレームワークとNetCoreのための私の解決策を追加します。
私はネットフレームワークの実装のためにこれを使用します:
public static class EnumerationExtension
{
public static string Description( this Enum value )
{
// get attributes
var field = value.GetType().GetField( value.ToString() );
var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );
// return description
return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
}
}
私はこれを行うには、それを修正してこれはNetCoreのために仕事をしません。
public static class EnumerationExtension
{
public static string Description( this Enum value )
{
// get attributes
var field = value.GetType().GetField( value.ToString() );
var attributes = field.GetCustomAttributes( false );
// Description is in a hidden Attribute class called DisplayAttribute
// Not to be confused with DisplayNameAttribute
dynamic displayAttribute = null;
if (attributes.Any())
{
displayAttribute = attributes.ElementAt( 0 );
}
// return description
return displayAttribute?.Description ?? "Description Not Found";
}
}
列挙例:
public enum ExportTypes
{
[Display( Name = "csv", Description = "text/csv" )]
CSV = 0
}
追加静的のサンプル使用方法:
var myDescription = myEnum.Description();
新しいC#言語の機能のいくつかの利点を生かし、あなたは行数を減らすことができます
public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumVal) where TAttribute : Attribute
{
var memberInfo = enumVal.GetType().GetMember(enumVal.ToString());
return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType<TAttribute>().FirstOrDefault();
}
public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute<DescriptionAttribute>()?.Description ?? enumValue.ToString();
私はセットアップにこの答え素晴らしかった列挙型の属性からコンボボックス。
Iその後、コードに必要な、私はボックスから選択を取得し、正しい型に列挙型を返すことができるという逆のようにします。
私はまた、属性が
行方不明になったケースを処理するコードを修正しました次の人の利益のために、ここで私の最終的な解決策である。
public static class Program
{
static void Main(string[] args)
{
// display the description attribute from the enum
foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour)))
{
Console.WriteLine(EnumExtensions.ToName(type));
}
// Get the array from the description
string xStr = "Yellow";
Colour thisColour = EnumExtensions.FromName<Colour>(xStr);
Console.ReadLine();
}
public enum Colour
{
[Description("Colour Red")]
Red = 0,
[Description("Colour Green")]
Green = 1,
[Description("Colour Blue")]
Blue = 2,
Yellow = 3
}
}
public static class EnumExtensions
{
// This extension method is broken out so you can use a similar pattern with
// other MetaData elements in the future. This is your base method for each.
public static T GetAttribute<T>(this Enum value) where T : Attribute
{
var type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
// check if no attributes have been specified.
if (((Array)attributes).Length > 0)
{
return (T)attributes[0];
}
else
{
return null;
}
}
// This method creates a specific call to the above method, requesting the
// Description MetaData attribute.
public static string ToName(this Enum value)
{
var attribute = value.GetAttribute<DescriptionAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
/// <summary>
/// Find the enum from the description attribute.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="desc"></param>
/// <returns></returns>
public static T FromName<T>(this string desc) where T : struct
{
string attr;
Boolean found = false;
T result = (T)Enum.GetValues(typeof(T)).GetValue(0);
foreach (object enumVal in Enum.GetValues(typeof(T)))
{
attr = ((Enum)enumVal).ToName();
if (attr == desc)
{
result = (T)enumVal;
found = true;
break;
}
}
if (!found)
{
throw new Exception();
}
return result;
}
}
}
この拡張方法は、そのXmlEnumAttributeを使用して列挙値の文字列表現を取得します。何XmlEnumAttributeが存在しない場合、それはバックenum.ToStringにフォール()。
public static string ToStringUsingXmlEnumAttribute<T>(this T enumValue)
where T: struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
string name;
var type = typeof(T);
var memInfo = type.GetMember(enumValue.ToString());
if (memInfo.Length == 1)
{
var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);
if (attributes.Length == 1)
{
name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name;
}
else
{
name = enumValue.ToString();
}
}
else
{
name = enumValue.ToString();
}
return name;
}
そして、あなたは名の完全なリストが必要な場合は、のような何かを行うことができます。
typeof (PharmacyConfigurationKeys).GetFields()
.Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
.Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
あなたのenum
は、ここでの回答の多くのいくつかの拡張機能を使用していくつかのバグにぶつかるかもしれませんEquals
のような値が含まれている場合。通常typeof(YourEnum).GetMember(YourEnum.Value)
があなたのMemberInfo
のenum
ある一つの値だけを、戻ってくることが想定されるためです。ここで少しより安全なバージョンをhref="https://stackoverflow.com/a/9276348/209259">います。
public static class AttributeExtensions
{
#region Methods
public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
{
var type = enumValue.GetType();
var memberInfo = type.GetMember(enumValue.ToString());
var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
return attribute is T ? (T)attribute : null;
}
#endregion
}
Guysが、それは私があなたと私の解決策を共有する場合に役立ちます。 カスタム属性の定義:
[AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
public class EnumDisplayName : Attribute
{
public string Name { get; private set; }
public EnumDisplayName(string name)
{
Name = name;
}
}
今、私は内部のHtmlHelperの拡張のHtmlHelperの定義のそれを必要とするのでます:
public static class EnumHelper
{
public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
{
//Get every fields from enum
var fields = priceType.GetType().GetFields();
//Foreach field skipping 1`st fieldw which keeps currently sellected value
for (int i = 0; i < fields.Length;i++ )
{
//find field with same int value
if ((int)fields[i].GetValue(priceType) == (int)priceType)
{
//get attributes of found field
var attributes = fields[i].GetCustomAttributes(false);
if (attributes.Length > 0)
{
//return name of found attribute
var retAttr = (EnumDisplayName)attributes[0];
return retAttr.Name;
}
}
}
//throw Error if not found
throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
}
}
希望は、それが役立ちます。
public enum DataFilters
{
[Display(Name= "Equals")]
Equals = 1,// Display Name and Enum Name are same
[Display(Name= "Does Not Equal")]
DoesNotEqual = 2, // Display Name and Enum Name are different
}
今では、この場合にエラーを生成します1「に等しい」
public static string GetDisplayName(this Enum enumValue)
{
var enumMember = enumValue.GetType().GetMember(enumValue.ToString()).First();
return enumMember.GetCustomAttribute<DisplayAttribute>() != null ? enumMember.GetCustomAttribute<DisplayAttribute>().Name : enumMember.Name;
}
それはので、同じリターン列挙名ではなく、表示名の場合 enumMember.GetCustomAttribute() 表示名と列挙型の名前が同じである場合はnullを取得します.....
また、あなたが次のことを行うことができます:
Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
{
{ FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
{ FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
};
、次で説明を取得ます:
string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
無反射が必要とされていないとして私の意見では、これは、あなたが達成したい何をして、より効率的な方法です..
またName_Without_Spaces
のような列挙型の値を定義することができ、あなたがスペースでアンダースコアを置き換えるために記述の利用Name_Without_Spaces.ToString().Replace('_', ' ')
をしたいときます。