I would like to know if it is possible to get attributes of the enum values and not of the enum itself? For example, suppose I have the following enum:
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
What I want is given the enum type, produce 2-tuples of enum string value and its description.
Value was easy:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
But how do I get description attribute's value, to populate Tuple.Desc? I can think of how to do it if the Attribute belongs to the enum itself, but I am at a loss as to how to get it from the value of the enum.
This should do what you need.
try
{
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;
}
catch
{
return FunkyAttributesEnum.NameWithoutSpaces1.ToString()
}
This piece of code should give you a nice little extension method on any enum that lets you retrieve a generic attribute. I believe it's different to the lambda function above because it's simpler to use and slightly - you only need to pass in the generic type.
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><![CDATA[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;
}
}
Usage would then be:
string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;
This is a generic implementation using a lambda for the selection
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);
}
Call it like this:
string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
I've merged a couple of the answers here to create a little more extensible solution. I'm providing it just in case it's helpful to anyone else in the future. Original posting here.
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;
}
}
This solution creates a pair of extension methods on Enum. The first allows you to use reflection to retrieve any attribute associated with your value. The second specifically calls retrieves the DescriptionAttribute and returns it's Description value.
As an example, consider using the DescriptionAttribute attribute from 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
}
To use the above extension method, you would now simply call the following:
Console.WriteLine(Days.Mon.ToName());
or
var day = Days.Mon;
Console.WriteLine(day.ToName());
In addition to AdamCrawford response, I've further created a more specialized extension methods that feed of it to get the description.
public static string GetAttributeDescription(this Enum enumValue)
{
var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
return attribute == null ? String.Empty : attribute.Description;
}
hence, to get the description, you could either use the original extension method as
string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description
or you could simply call the the extension method here as:
string desc = myEnumVariable.GetAttributeDescription();
Which should hopefully make your code a bit more readable.
Fluent one liner...
Here I'm using the DisplayAttribute which contains both the Name and Description properties.
public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
return enumType.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
}
Example
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);
}
Output
Name: Sea cruise
Description: Cruising on a dinghy
Here is code to get information from a Display attribute. It uses a generic method to retrieve the attribute. If the attribute is not found it converts the enum value to a string with pascal/camel case converted to title case (code obtained here)
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();
}
}
And this is the extension method for strings for converting to title case:
/// <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 "));
}
Get the dictionary from enum.
public static IDictionary<string, int> ToDictionary(this Type enumType)
{
return Enum.GetValues(enumType)
.Cast<object>()
.ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k);
}
Now call this like...
var dic = typeof(ActivityType).ToDictionary();
EnumDecription Ext Method
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
}
I this answer to setup a combo box from an enum attributes which was great.
I then needed to code the reverse so that I can get the selection from the box and return the enum in the correct type.
I also modified the code to handle the case where an attribute was missing
For the benefits of the next person, here is my final solution
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;
}
}
}
Performance matters
If you want better performance this is the way to go:
public static class AdvancedEnumExtensions
{
/// <summary>
/// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
/// </summary>
public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
{
return GetField(value)?.GetCustomAttribute<T>(inherit: false);
}
/// <summary>
/// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
/// </summary>
public static FieldInfo GetField(this Enum value)
{
ulong u64 = ToUInt64(value);
return value
.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
.FirstOrDefault();
}
/// <summary>
/// Checks if an enum constant is defined for this enum value
/// </summary>
public static bool IsDefined(this Enum value)
{
return GetField(value) != null;
}
/// <summary>
/// Converts the enum value to UInt64
/// </summary>
public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);
private static ulong ToUInt64(object value)
{
switch (Convert.GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Char:
case TypeCode.Boolean:
return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
default: throw new InvalidOperationException("UnknownEnumType");
}
}
}
Why does this have better performance?
Because the built-in methods all use code very similar to this except they also run a bunch of other code we don't care about. C#'s Enum code is quite horrible in general.
The above code has been Linq-ified and streamlined so it only contains the bits we care about.
Why is the built-in code slow?
First regarding Enum.ToString() -vs- Enum.GetName(..)
Always use the latter. (Or better yet neither, as will become clear below.)
ToString() uses the latter internally, but again, also does a bunch of other stuff we don't want, e.g. tries to combine flags, print out numbers etc. We are only interested in constants defined inside the enum.
Enum.GetName in turn gets all fields, creates a string array for all names, uses the above ToUInt64 on all of their RawConstantValues to create an UInt64 array of all values, sorts both arrays according to the UInt64 value, and finally gets the name from the name-array by doing a BinarySearch in the UInt64-array to find the index of the value we wanted.
...and then we throw the fields and the sorted arrays away use that name to find the field again.
One word: "Ugh!"
For some programmer humor, a one liner as a joke:
public static string GetDescription(this Enum value) => value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : string.Empty;
In a more readable form:
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
public static class EnumExtensions
{
// get description from enum:
public static string GetDescription(this Enum value)
{
return value.GetType().
GetMember(value.ToString()).
First().
GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute
? attribute.Description
: throw new Exception($"Enum member '{value.GetType()}.{value}' doesn't have a [DescriptionAttribute]!");
}
// get enum from description:
public static T GetEnum<T>(this string description) where T : Enum
{
foreach (FieldInfo fieldInfo in typeof(T).GetFields())
{
if (fieldInfo.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute && attribute.Description == description)
return (T)fieldInfo.GetRawConstantValue();
}
throw new Exception($"Enum '{typeof(T)}' doesn't have a member with a [DescriptionAttribute('{description}')]!");
}
}
Here's the .NET Core version of AdamCrawford's answer, using 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];
}
}
Adding my solution for Net Framework and NetCore.
I used this for my Net Framework implementation:
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";
}
}
This doesn't work for NetCore so I modified it to do this:
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";
}
}
Enumeration Example:
public enum ExportTypes
{
[Display( Name = "csv", Description = "text/csv" )]
CSV = 0
}
Sample Usage for either static added:
var myDescription = myEnum.Description();
If your enum contains a value like Equals you might bump into a few bugs using some extensions in a lot of answers here. This is because it is normally assumed that typeof(YourEnum).GetMember(YourEnum.Value) would return only one value, which is the MemberInfo of your enum. Here's a slightly safer version Adam Crawford's answer.
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
}
Model
The model in which we fill our values
public class MemberTypeModel : IDto
{
public string MemberAttributeName { get; set; }
public string MemberName { get; set; }
public int MemberValue { get; set; }
}
Enum
Our target is the enum
public enum MemberType
{
[FieldText("Yönetim Kurul Üyesi")]
BoardManager = 0,
[FieldText("Temsilci")]
Representative = 1,
[FieldText("Üye")]
Member = 2
}
Helper Method
The helper method we will use to fetch the custom attribute object
public T GetMemberCustomText<T>(MemberType memberType) where T : Attribute
{
var enumType = memberType.GetType();
var name = Enum.GetName(enumType, memberType);
return enumType.GetField(name).GetCustomAttributes(false).OfType<T>().SingleOrDefault();
}
Get Method
First we pull enum values and cast them to enum type. Then, with the Linq selection query we know;
MemberAttributeName field with helper method,
MemberName field with Enum.GetName method,
Casting the MemberValue field to an int type as well,
We fill it out and turn it into a list.
public List<MemberTypeModel> GetMemberTypes()
{
var memberTypes = Enum.GetValues(typeof(MemberType))
.Cast<MemberType>()
.Select(et => new MemberTypeModel
{
MemberAttributeName = GetMemberCustomText<FieldText>(et).Text,
MemberName = Enum.GetName(et.GetType(), et),
MemberValue = (int)et
}).ToList();
return memberTypes;
}
I implemented this extension method to get the description from enum values. It works for all kind of enums.
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();
}
}
Taking advantage of some of the newer C# language features, you can reduce the line count:
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();
Bryan Rowe and AdamCrawford thanks for your answers!
But if somebody need method for get Discription (not extension) you can use it:
string GetEnumDiscription(Enum EnumValue)
{
var type = EnumValue.GetType();
var memInfo = type.GetMember(EnumValue.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? ((DescriptionAttribute)attributes[0]).Description : null;
}
This extension method will obtain a string representation of an enum value using its XmlEnumAttribute. If no XmlEnumAttribute is present, it falls back to 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;
}
And if you want the full list of names you can do something like
typeof (PharmacyConfigurationKeys).GetFields()
.Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
.Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
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
}
Now it will produce error in this case 1 "Equals"
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;
}
so if it is same return enum name rather than display name because
enumMember.GetCustomAttribute()
gets null if displayname and enum name are same.....
The NuGet package Enums.Net has good support for this:
var value = FunkyAttributesEnum.NameWithoutSpaces1;
string description = value.AsString(EnumFormat.Description); // => "Name With Spaces1"
The package is simple, intuitive, and complete.
It's type-safe and has cache to avoid recurring reflection.
The GitHub repository has more information, including the limitations of the native Enum and a demo of functionality:
Getting attributes;
Flag operations;
Enum formats (for ToString or to parse the enum from string);
Rich iteration of all values with Enums.GetMembers<MyEnum>();
Etc.
Alternatively, you could do the following:
Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
{
{ FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
{ FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
};
And get the description with the following:
string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
In my opinion this is a more efficient way of doing what you want to accomplish, as no reflection is needed..
Guys if it helps I will share with you my solution:
Definition of Custom attribute:
[AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
public class EnumDisplayName : Attribute
{
public string Name { get; private set; }
public EnumDisplayName(string name)
{
Name = name;
}
}
Now because I needed it inside of HtmlHelper definition of HtmlHelper Extension:
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");
}
}
Hope it helps
Alternatively, you could do the following:
List<SelectListItem> selectListItems = new List<SelectListItem>();
foreach (var item in typeof(PaymentTerm).GetEnumValues())
{
var type = item.GetType();
var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
selectListItems.Add(new SelectListItem(name, type.Name));
}
This is how I solved it without using custom helpers or extensions with .NET core 3.1.
Class
public enum YourEnum
{
[Display(Name = "Suryoye means Arameans")]
SURYOYE = 0,
[Display(Name = "Oromoye means Syriacs")]
OROMOYE = 1,
}
Razor
#using Enumerations
foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
{
<h1>#name.Text</h1>
}
I have created an extension method that will return description of all the elements in an enum in C#.
public static List<string> GetAllEnumDescriptions(this Type enumType)
{
try
{
var enumList = Enum.GetValues(enumType).Cast<Enum>().ToList();
List<string> result = new List<string>();
foreach (var enumItem in enumList)
{
result.Add(enumItem.EnumDescription());
}
return result;
}
catch (Exception ex)
{
return new List<string>();
}
}
This method will add the description of the elements in an enum using the inbuilt EnumDescription() extension method.
I got an Int16 value, from the database, and need to convert this to an enum type. This is unfortunately done in a layer of the code that knows very little about the objects except for what it can gather through reflection.
As such, it ends up calling Convert.ChangeType which fails with an invalid cast exception.
I found what I consider a smelly workaround, like this:
String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);
Is there a better way, so that I don't have to move through this String operation?
Here's a short, but complete, program that can be used if anyone need to experiment:
using System;
public class MyClass
{
public enum DummyEnum
{
Value0,
Value1
}
public static void Main()
{
Int16 value = 1;
Type destinationType = typeof(DummyEnum);
String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);
Console.WriteLine("" + value + " = " + enumValue);
}
}
Enum.ToObject(.... is what you're looking for!
C#
StringComparison enumValue = (StringComparison)Enum.ToObject(typeof(StringComparison), 5);
VB.NET
Dim enumValue As StringComparison = CType([Enum].ToObject(GetType(StringComparison), 5), StringComparison)
If you do a lot of Enum converting try using the following class it will save you alot of code.
public class Enum<EnumType> where EnumType : struct, IConvertible
{
/// <summary>
/// Retrieves an array of the values of the constants in a specified enumeration.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType[] GetValues()
{
return (EnumType[])Enum.GetValues(typeof(EnumType));
}
/// <summary>
/// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType Parse(string name)
{
return (EnumType)Enum.Parse(typeof(EnumType), name);
}
/// <summary>
/// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
/// </summary>
/// <param name="name"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType Parse(string name, bool ignoreCase)
{
return (EnumType)Enum.Parse(typeof(EnumType), name, ignoreCase);
}
/// <summary>
/// Converts the specified object with an integer value to an enumeration member.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
/// <remarks></remarks>
public static EnumType ToObject(object value)
{
return (EnumType)Enum.ToObject(typeof(EnumType), value);
}
}
Now instead of writing (StringComparison)Enum.ToObject(typeof(StringComparison), 5); you can simply write Enum<StringComparison>.ToObject(5);.
Based on the #Peter's answer here is the method for Nullable<int> to Enum conversion:
public static class EnumUtils
{
public static bool TryParse<TEnum>(int? value, out TEnum result)
where TEnum: struct, IConvertible
{
if(!value.HasValue || !Enum.IsDefined(typeof(TEnum), value)){
result = default(TEnum);
return false;
}
result = (TEnum)Enum.ToObject(typeof(TEnum), value);
return true;
}
}
Using EnumUtils.TryParse<YourEnumType>(someNumber, out result) becomes useful for many scenarios. For example, WebApi Controller in Asp.NET does not have default protection against invalid Enum params. Asp.NET will just use default(YourEnumType) value, even if some passes null, -1000, 500000, "garbage string" or totally ignores the parameter. Moreover, ModelState will be valid in all these cases, so one of the solution is to use int? type with custom check
public class MyApiController: Controller
{
[HttpGet]
public IActionResult Get(int? myEnumParam){
MyEnumType myEnumParamParsed;
if(!EnumUtils.TryParse<MyEnumType>(myEnumParam, out myEnumParamParsed)){
return BadRequest($"Error: parameter '{nameof(myEnumParam)}' is not specified or incorrect");
}
return this.Get(washingServiceTypeParsed);
}
private IActionResult Get(MyEnumType myEnumParam){
// here we can guarantee that myEnumParam is valid
}
If you are storing an Enum in a DataTable but don't know which column is an enum and which is a string/int, you can access the value this way:
foreach (DataRow dataRow in myDataTable.Rows)
{
Trace.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
foreach (DataColumn dataCol in myDataTable.Columns)
{
object v = dataRow[dataCol];
Type t = dataCol.DataType;
bool e = false;
if (t.IsEnum) e = true;
Trace.WriteLine((dataCol.ColumnName + ":").PadRight(30) +
(e ? Enum.ToObject(t, v) : v));
}
}
I've got
public enum Als
{
[StringValue("Beantwoord")] Beantwoord = 0,
[StringValue("Niet beantwoord")] NietBeantwoord = 1,
[StringValue("Geselecteerd")] Geselecteerd = 2,
[StringValue("Niet geselecteerd")] NietGeselecteerd = 3,
}
with
public class StringValueAttribute : Attribute
{
private string _value;
public StringValueAttribute(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
And I would like to put the value from the item I selected of a combobox into a int:
int i = (int)(Als)Enum.Parse(typeof(Als), (string)cboAls.SelectedValue); //<- WRONG
Is this possible, and if so, how? (the StringValue matches the value selected from the combobox).
Here's a helper method that should point you in the right direction.
protected Als GetEnumByStringValueAttribute(string value)
{
Type enumType = typeof(Als);
foreach (Enum val in Enum.GetValues(enumType))
{
FieldInfo fi = enumType.GetField(val.ToString());
StringValueAttribute[] attributes = (StringValueAttribute[])fi.GetCustomAttributes(
typeof(StringValueAttribute), false);
StringValueAttribute attr = attributes[0];
if (attr.Value == value)
{
return (Als)val;
}
}
throw new ArgumentException("The value '" + value + "' is not supported.");
}
And to call it, just do the following:
Als result = this.GetEnumByStringValueAttribute<Als>(ComboBox.SelectedValue);
This probably isn't the best solution though as it's tied to Als and you'll probably want to make this code re-usable. What you'll probably want to strip out the code from my solution to return you the attribute value and then just use Enum.Parse as you are doing in your question.
I'm using the DescriptionAttribute from Microsoft and the following extension method:
public static string GetDescription(this Enum value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
DescriptionAttribute[] attributes =
(DescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}
Here are a couple extension methods that I use for this exact purpose, I've rewritten these to use your StringValueAttribute, but like Oliver I use the DescriptionAttribute in my code.
public static T FromEnumStringValue<T>(this string description) where T : struct {
Debug.Assert(typeof(T).IsEnum);
return (T)typeof(T)
.GetFields()
.First(f => f.GetCustomAttributes(typeof(StringValueAttribute), false)
.Cast<StringValueAttribute>()
.Any(a => a.Value.Equals(description, StringComparison.OrdinalIgnoreCase))
)
.GetValue(null);
}
This can be made slightly more simple in .NET 4.5:
public static T FromEnumStringValue<T>(this string description) where T : struct {
Debug.Assert(typeof(T).IsEnum);
return (T)typeof(T)
.GetFields()
.First(f => f.GetCustomAttributes<StringValueAttribute>()
.Any(a => a.Value.Equals(description, StringComparison.OrdinalIgnoreCase))
)
.GetValue(null);
}
And to call it, just do the following:
Als result = ComboBox.SelectedValue.FromEnumStringValue<Als>();
Conversely, here's a function to get the string from an enum value:
public static string StringValue(this Enum enumItem) {
return enumItem
.GetType()
.GetField(enumItem.ToString())
.GetCustomAttributes<StringValueAttribute>()
.Select(a => a.Value)
.FirstOrDefault() ?? enumItem.ToString();
}
And to call it:
string description = Als.NietBeantwoord.StringValue()
Coming here from duplicate links of this highly upvoted question and answer, here is a method that works with C# 7.3's new Enum type constraint. Note that you also need to specify that it is also a struct so that you can make it the nullable TEnum? or else you will get an error.
public static TEnum? GetEnumFromDescription<TEnum>(string description)
where TEnum : struct, Enum
{
var comparison = StringComparison.OrdinalIgnoreCase;
foreach (var field in typeof(TEnum).GetFields())
{
var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attribute != null)
{
if (string.Compare(attribute.Description, description, comparison) == 0)
return (TEnum)field.GetValue(null);
}
if (string.Compare(field.Name, description, comparison) == 0)
return (TEnum)field.GetValue(null);
}
return null;
}
Not sure if I am missing something here, can you not do this,
Als temp = (Als)combo1.SelectedItem;
int t = (int)temp;
To parse a string value based on attribute values applied to enum members I'd recommend you use my Enums.NET open source library.
For a custom attribute like the StringValueAttribute you would do this.
Register and store a custom EnumFormat for StringValueAttribute.Value.
Format = Enums.RegisterCustomEnumFormat(m => m.Attributes.Get<StringValueAttribute>()?.Value);
Then use the custom EnumFormat.
Als result = Enums.Parse<Als>("Niet beantwoord", Format); // result == Als.NietBeantwoord
If you were instead using a built-in attribute such as the DescriptionAttribute you could just do this.
Als result = Enums.Parse<Als>("Niet beantwoord", EnumFormat.Description);
In case you're interested, this is how you'd get the string value associated with an enum value.
string value = Als.NietBeantwoord.AsString(Format); // value == "Niet beantwoord"
I made a more generic solution.
You can use it with any attribute and even with other types than string.
using System;
namespace EnumTest
{
public static class EnumExtensions
{
#region Get enum from Attribute
/// <summary>
/// Searches the enum element which has a [attributeType] attribute with a attributePropertyName equivalent to searchValue.
/// Throws exception, if there is no enum element found which has a [attributeType] attribute with a attributePropertyName equivalent to searchValue.
/// </summary>
/// <param name="attributeType">the type of the attribute. e.g. typeof(System.ComponentModel.DescriptionAttribute)</param>
/// <param name="attributePropertyName">the property of the attribute to search. At DescriptionAttribute, this is "Description"</param>
/// <param name="searchValue">the value to search</param>
public static TEnum FromAttributeValueToEnum<TEnum>(Type attributeType, string attributePropertyName, object searchValue)
where TEnum : struct, Enum
{
TEnum? result = FromAttributeValueToNullableEnum<TEnum>(attributeType, attributePropertyName, searchValue);
if (result.HasValue)
{
return result.Value;
}
Type enumType = typeof(TEnum);
throw new ArgumentException($"The enum type {enumType.FullName} has no element with a {attributeType.FullName} with {attributePropertyName} property equivalent to '{searchValue}'");
}
/// <summary>
/// Searches the enum element which has a [attributeType] attribute with a attributePropertyName equivalent to searchValue.
/// Returns fallBackValue, if there is no enum element found which has a [attributeType] attribute with a attributePropertyName equivalent to searchValue.
/// </summary>
/// <param name="attributeType">the type of the attribute. e.g. typeof(System.ComponentModel.DescriptionAttribute)</param>
/// <param name="attributePropertyName">the property of the attribute to search. At DescriptionAttribute, this is "Description"</param>
/// <param name="searchValue">the value to search</param>
public static TEnum FromAttributeValueToEnum<TEnum>(Type attributeType, string attributePropertyName, object searchValue, TEnum fallBackValue)
where TEnum : struct, Enum
{
TEnum? result = FromAttributeValueToNullableEnum<TEnum>(attributeType, attributePropertyName, searchValue);
if (result.HasValue)
{
return result.Value;
}
return fallBackValue;
}
/// <summary>
/// Searches the enum element which has a [attributeType] attribute with a attributePropertyName equivalent to searchValue.
/// Returns null, if there is no enum element found which has a [attributeType] attribute with a attributePropertyName equivalent to searchValue.
/// </summary>
/// <param name="attributeType">the type of the attribute. e.g. typeof(System.ComponentModel.DescriptionAttribute)</param>
/// <param name="attributePropertyName">the property of the attribute to search. At DescriptionAttribute, this is "Description"</param>
/// <param name="searchValue">the value to search</param>
public static TEnum? FromAttributeValueToNullableEnum<TEnum>(Type attributeType, string attributePropertyName, object searchValue)
where TEnum : struct, Enum
{
Type enumType = typeof(TEnum);
if (!enumType.IsEnum)
{
throw new ArgumentException($"The type {enumType.FullName} is no Enum!");
}
if (attributeType == null)
{
throw new ArgumentNullException(nameof(attributeType));
}
if (!typeof(Attribute).IsAssignableFrom(attributeType))
{
throw new ArgumentException($"The type {attributeType.FullName} is no Attribute!", nameof(attributeType));
}
var propertyInfoAttributePropertyName = attributeType.GetProperty(attributePropertyName);
if (propertyInfoAttributePropertyName == null)
{
throw new ArgumentException($"The type {attributeType.FullName} has no (public) property with name {attributePropertyName}", nameof(attributeType));
}
foreach (var field in enumType.GetFields())
{
if (field.IsSpecialName)
{
continue;
}
var attributes = Attribute.GetCustomAttributes(field, attributeType);
if (attributes.Length == 0)
{
continue;
}
foreach (var attribute in attributes)
{
object attributePropertyValue = propertyInfoAttributePropertyName.GetValue(attribute);
if (attributePropertyValue == null)
{
continue;
}
if (attributePropertyValue.Equals(searchValue))
{
return (TEnum)field.GetValue(null);
}
}
}
return null;
}
#endregion
}
}
#RubenHerman's initial post:
Als Beantwoord = EnumExtensions.FromAttributeValueToEnum<Als>(typeof(StringValueAttribute), nameof(StringValueAttribute.Value), "Beantwoord");
Advanced sample:
public class IntValueAttribute : Attribute
{
public IntValueAttribute(int value)
{
Value = value;
}
public int Value { get; private set; }
}
public enum EnumSample
{
[Description("Eins")]
[IntValue(1)]
One,
[Description("Zwei")]
[IntValue(2)]
Two,
[Description("Drei")]
[IntValue(3)]
Three
}
EnumSample one = EnumExtensions.FromAttributeValueToEnum<EnumSample>(typeof(DescriptionAttribute), nameof(DescriptionAttribute.Description), "Eins");
EnumSample two = EnumExtensions.FromAttributeValueToEnum<EnumSample>(typeof(IntValueAttribute), nameof(IntValueAttribute.Value), 2);
I have my enumHelper class that contains these:
public static IList<T> GetValues()
{
IList<T> list = new List<T>();
foreach (object value in Enum.GetValues(typeof(T)))
{
list.Add((T)value);
}
return list;
}
and
public static string Description(Enum value)
{
Attribute DescAttribute = LMIGHelper.GetAttribute(value, typeof(DescriptionAttribute));
if (DescAttribute == null)
return value.ToString();
else
return ((DescriptionAttribute)DescAttribute).Description;
}
my enum is something like:
public enum OutputType
{
File,
[Description("Data Table")]
DataTable
}
So far so good. All the previous work fine.
Now I want to add a new helper to return BindingList>, so I can link any enum to any combo using
BindingList<KeyValuePair<OutputType, string>> list = Enum<OutputType>.GetBindableList();
cbo.datasource=list;
cbo.DisplayMember="Value";
cbo.ValueMember="Key";
For that I added:
public static BindingList<KeyValuePair<T, string>> GetBindingList()
{
BindingList<KeyValuePair<T, string>> list = new BindingList<KeyValuePair<T, string>>();
foreach (T value in Enum<T>.GetValues())
{
string Desc = Enum<T>.Description(value);
list.Add(new KeyValuePair<T, string>(value, Desc));
}
return list;
}
But "Enum.Description(value)" is not even compiling:
Argument '1': cannot convert from 'T' to 'System.Enum'
How can I do that? Is that even possible?
Thank you.
Take a look at this article. You can do this using the System.ComponentModel.DescriptionAttribute or creating your own attribute:
/// <summary>
/// Provides a description for an enumerated type.
/// </summary>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,
AllowMultiple = false)]
public sealed class EnumDescriptionAttribute : Attribute
{
private string description;
/// <summary>
/// Gets the description stored in this attribute.
/// </summary>
/// <value>The description stored in the attribute.</value>
public string Description
{
get
{
return this.description;
}
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="EnumDescriptionAttribute"/> class.
/// </summary>
/// <param name="description">The description to store in this attribute.
/// </param>
public EnumDescriptionAttribute(string description)
: base()
{
this.description = description;
}
}
You then need to decorate the enum values with this new attribute:
public enum SimpleEnum
{
[EnumDescription("Today")]
Today,
[EnumDescription("Last 7 days")]
Last7,
[EnumDescription("Last 14 days")]
Last14,
[EnumDescription("Last 30 days")]
Last30,
[EnumDescription("All")]
All
}
All of the "magic" takes place in the following extension methods:
/// <summary>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// </summary>
public static class EnumHelper
{
/// <summary>
/// Gets the <see cref="DescriptionAttribute" /> of an <see cref="Enum" />
/// type value.
/// </summary>
/// <param name="value">The <see cref="Enum" /> type value.</param>
/// <returns>A string containing the text of the
/// <see cref="DescriptionAttribute"/>.</returns>
public static string GetDescription(this Enum value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
EnumDescriptionAttribute[] attributes =
(EnumDescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}
/// <summary>
/// Converts the <see cref="Enum" /> type to an <see cref="IList" />
/// compatible object.
/// </summary>
/// <param name="type">The <see cref="Enum"/> type.</param>
/// <returns>An <see cref="IList"/> containing the enumerated
/// type value and description.</returns>
public static IList ToList(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
ArrayList list = new ArrayList();
Array enumValues = Enum.GetValues(type);
foreach (Enum value in enumValues)
{
list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
}
return list;
}
}
Finally, you can then simply bind the combobox:
combo.DataSource = typeof(SimpleEnum).ToList();
You should change:
public static string Description(Enum value)
{
...
}
to
public static string Description(T value)
{
...
}
so it accepts a value of the enumeration. Now here is where it gets tricky: you have a value, but attributes decorate the field which holds the value.
You actually need to reflect over the enumeration's fields and check the value of each against the value you've been given (results should be cached for performance):
foreach(var field in typeof(T).GetFields())
{
T fieldValue;
try
{
fieldValue = (T) field.GetRawConstantValue();
}
catch(InvalidOperationException)
{
// For some reason, one of the fields returned is {Int32 value__},
// which throws an InvalidOperationException if you try and retrieve
// its constant value.
//
// I am unsure how to check for this state before
// attempting GetRawConstantValue().
continue;
}
if(fieldValue == value)
{
var attribute = LMIGHelper.GetAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
}
Edit addressing the follow-up question
The FillComboFromEnum method is missing the type parameter for the enum. Try this:
public static void FillComboFromEnum<T>(ComboBox Cbo, BindingList<KeyValuePair<T, string>> List) where T : struct
Notice I constrained the type to be a struct. It's not a full enumeration constraint, but it's closer than nothing.
Enum doesn't have a Description() method. The best you could do is have your enum implement an interface that has the Description() method. If you do that, then you can have
public static BindingList<KeyValuePair<T extends _interface_, String>> getBindingList()
and then inside of that you can refer to
T foo = ...?
foo.Description(...);