列挙型の属性ではなく、列挙型の値の属性を取得できるかどうかを知りたいですか。たとえば、次のような列挙型があるとします。
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
私が欲しいのはenum型を与えられ、enum文字列値とその説明の2タプルを生成します。
値は簡単でした:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
しかし、Tuple.Descを生成するために、description属性の値を取得するにはどうすればよいですか? Attributeがenum自体に属している場合はどうすればよいかを考えることができますが、enumの値からそれを取得する方法については迷います。
これはあなたが必要とすることをするべきです。
var type = typeof(FunkyAttributesEnum);
var memInfo = type.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var mem = memInfo.FirstOrDefault(m => m.DeclaringType == type);
var attributes = mem.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[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);
もう少し拡張性の高いソリューションを作成するために、ここでいくつかの答えをマージしました。念のために提供していますが、将来的に他の誰かに役立つ場合があります。元の投稿 はこちら 。
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;
}
}
このソリューションはEnum上で一対の拡張メソッドを作成します。 1つ目は、リフレクションを使用して自分の値に関連付けられている属性を取得することを可能にします。 2番目の呼び出しは、特にDescriptionAttribute
を呼び出し、そのDescription
値を返します。
例として、System.ComponentModel
のDescriptionAttribute
属性を使用することを検討してください。
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();
うまくいけばあなたのコードをもう少し読みやすくするはずです。
流暢なライナー...
ここでは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
これがDisplay属性から情報を取得するためのコードです。一般的な方法を使用して属性を取得します。属性が見つからない場合は、enum値をPascal/camelケースをtitleケースに変換した文字列に変換します(ここで取得したコード)。
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 "));
}
Enumから辞書を入手してください。
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();
}
}
これは、 System.Reflection.TypeExtensions を使用した、AdamCrawfordの答えの.NET Coreバージョンです。
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];
}
}
Net FrameworkとNetCoreに私のソリューションを追加する。
私はこれを私のNet Frameworkの実装に使いました。
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();
この答えはenum属性からコンボボックスを設定するための素晴らしいものでした。
それから、ボックスから選択を取得して正しい型で列挙を返すことができるように、逆をコーディングする必要がありました。
私はまた、属性が欠けているケースを処理するためにコードを修正しました
次の人の利益のために、これが私の最後の解決策です
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;
}
あなたのenum
がEquals
のような値を含んでいるなら、ここで多くの答えの中でいくつかの拡張を使っていくつかのバグにぶつかるかもしれません。これは通常、typeof(YourEnum).GetMember(YourEnum.Value)
が1つの値のみを返すと想定されているからです。それはあなたのMemberInfo
のenum
です。これは少し安全なバージョンです Adam Crawfordの答え 。
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
}
そして、あなたが名前の完全なリストが欲しいなら、あなたは以下のようなことをすることができます
typeof (PharmacyConfigurationKeys).GetFields()
.Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
.Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
それが私の解決策を共有するのを助けるならみんな:カスタム属性の定義:
[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;
}
そのため、displaynameとenum nameが同じ場合は、enumMember.GetCustomAttribute()がnullになるため、表示名ではなく列挙名が返される場合.