Get Enum from Description attribute
Solution 1
public static class EnumEx
{
public static T GetValueFromDescription<T>(string description) where T : Enum
{
foreach(var field in typeof(T).GetFields())
{
if (Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
{
if (attribute.Description == description)
return (T)field.GetValue(null);
}
else
{
if (field.Name == description)
return (T)field.GetValue(null);
}
}
throw new ArgumentException("Not found.", nameof(description));
// Or return default(T);
}
}
Usage:
var panda = EnumEx.GetValueFromDescription<Animal>("Giant Panda");
Solution 2
rather than extension methods, just try a couple of static methods
public static class Utility
{
public static string GetDescriptionFromEnumValue(Enum value)
{
DescriptionAttribute attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof (DescriptionAttribute), false)
.SingleOrDefault() as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
public static T GetEnumValueFromDescription<T>(string description)
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException();
FieldInfo[] fields = type.GetFields();
var field = fields
.SelectMany(f => f.GetCustomAttributes(
typeof(DescriptionAttribute), false), (
f, a) => new { Field = f, Att = a })
.Where(a => ((DescriptionAttribute)a.Att)
.Description == description).SingleOrDefault();
return field == null ? default(T) : (T)field.Field.GetRawConstantValue();
}
}
and use here
var result1 = Utility.GetDescriptionFromEnumValue(
Animal.GiantPanda);
var result2 = Utility.GetEnumValueFromDescription<Animal>(
"Lesser Spotted Anteater");
Solution 3
The solution works good except if you have a Web Service.
You would need to do the Following as the Description Attribute is not serializable.
[DataContract]
public enum ControlSelectionType
{
[EnumMember(Value = "Not Applicable")]
NotApplicable = 1,
[EnumMember(Value = "Single Select Radio Buttons")]
SingleSelectRadioButtons = 2,
[EnumMember(Value = "Completely Different Display Text")]
SingleSelectDropDownList = 3,
}
public static string GetDescriptionFromEnumValue(Enum value)
{
EnumMemberAttribute attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(EnumMemberAttribute), false)
.SingleOrDefault() as EnumMemberAttribute;
return attribute == null ? value.ToString() : attribute.Value;
}
Solution 4
Should be pretty straightforward, its just the reverse of your previous method;
public static int GetEnumFromDescription(string description, Type enumType)
{
foreach (var field in enumType.GetFields())
{
DescriptionAttribute attribute
= Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))as DescriptionAttribute;
if(attribute == null)
continue;
if(attribute.Description == description)
{
return (int) field.GetValue(null);
}
}
return 0;
}
Usage:
Console.WriteLine((Animal)GetEnumFromDescription("Giant Panda",typeof(Animal)));
Solution 5
You can't extend Enum
as it's a static class. You can only extend instances of a type. With this in mind, you're going to have to create a static method yourself to do this; the following should work when combined with your existing method GetDescription
:
public static class EnumHelper
{
public static T GetEnumFromString<T>(string value)
{
if (Enum.IsDefined(typeof(T), value))
{
return (T)Enum.Parse(typeof(T), value, true);
}
else
{
string[] enumNames = Enum.GetNames(typeof(T));
foreach (string enumName in enumNames)
{
object e = Enum.Parse(typeof(T), enumName);
if (value == GetDescription((Enum)e))
{
return (T)e;
}
}
}
throw new ArgumentException("The value '" + value
+ "' does not match a valid enum name or description.");
}
}
And the usage of it would be something like this:
Animal giantPanda = EnumHelper.GetEnumFromString<Animal>("Giant Panda");
Related videos on Youtube
fearofawhackplanet
Updated on September 16, 2020Comments
-
fearofawhackplanet over 3 years
Possible Duplicate:
Finding an enum value by its Description AttributeI have a generic extension method which gets the
Description
attribute from anEnum
:enum Animal { [Description("")] NotSet = 0, [Description("Giant Panda")] GiantPanda = 1, [Description("Lesser Spotted Anteater")] LesserSpottedAnteater = 2 } public static string GetDescription(this Enum value) { FieldInfo field = value.GetType().GetField(value.ToString()); DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; return attribute == null ? value.ToString() : attribute.Description; }
so I can do...
string myAnimal = Animal.GiantPanda.GetDescription(); // = "Giant Panda"
now, I'm trying to work out the equivalent function in the other direction, something like...
Animal a = (Animal)Enum.GetValueFromDescription("Giant Panda", typeof(Animal));
-
fearofawhackplanet over 13 yearsyes it's getting the right enum type that I'm a bit stuck on.
-
Keith G about 12 yearsIf you add the "this" keyword in front of string ... public static T GetValueFromDescription<T>(this string description) ... it becomes an extension method and you can use syntax like: var x = "Giant Panda".GetValueFromDescription<Animal>();
-
Ren almost 11 yearsHow does one find if the description is not valid? with:
var x = EnumEx.GetValueFromDescription<Animal>("Dinosaur");
I know it would throw an exception. But what would x contain? -
nawfal almost 11 years@VenkatRenukaPrasad if it would throw anyway, then
x
cant have anything and you need not worry. Have an exception handling mechanism and handle it. -
nawfal almost 11 years
value.ToString()
is expensive, do not call it twice (.. if it matters)... -
nawfal almost 11 yearsThis is logically wrong (though can work in sensible scenarios). For instance if you have enum like
Animal { ("Giant Panda")GiantPanda, ("GiantPanda")Tiger }
and you callGetEnumFromString("GiantPanda")
, you will getGiantPanda
back, but I expectTiger
back. Have a function to either read enum string, or its description. Mixing both is a bad API style and can confuse clients. Or may be its good style to prevent user mistakes :) -
MEMark over 9 years@nawfal, expensive compared to what?
-
nawfal over 9 years@MEMark I dont remember what I was thinking then, but may be this
-
ErikE almost 9 yearsIf you change the method to add
where T : Enum
just before the open curly brace, you won't have to check thetypeof(T)
at runtime. -
max almost 9 years@ErikE
Enum
cannot be specified as a constraint (msdn.microsoft.com/en-us/library/56b2hk61.aspx) -
ATD over 8 years@ErikE you can't do that in C#.
-
ErikE over 8 years@ATD You're right, and I had forgotten that at the time. However, it is supported in the framework, so you can use Fody.ExtraConstraints to get the same effect, fully compiled and working as if
where T : Enum
had been specified. The syntax ispublic void MethodWithEnumConstraint<[EnumConstraint] T>() {...}
which gets compiled topublic void MethodWithEnumConstraint<T>() where T: struct, Enum {...}
. -
vbguyny about 8 yearsCode is great but forgot to mention that you need to include
using System.ComponentModel;
-
Atta H. over 6 yearsI used the same method for me, but as mentioned by @Keith as an extension method. It Worked
-
Damien Sawyer about 6 yearsMight want to do case insensitive comparisons instead like this. if (string.Equals(attribute.Description,description, StringComparison.InvariantCultureIgnoreCase)) return (T)field.GetValue(null); It caught me out.
-
DLeh about 6 yearsI've posted how you can convert this to the new c# 7.3
Enum
type constraint here stackoverflow.com/questions/2787506/… -
Ashish-BeJovial almost 6 yearswhat is the namespace of EnumMemberAttribute?
-
Prince Tegaton almost 6 yearsperfect.. bravo!!!
-
Jasmine over 5 yearsThis is exactly what I am looking for. Two highlights I loved are, my enum also starts with 1. Secondly, its enummember as its wcf. Thank you so much :)
-
Dennis about 5 yearsTo make the above code work better, change the line "foreach(var field in type.GetFields())" to "foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static))". Otherwise in the else below, the name of the field is 'value__' instead of the real name.
-
Shahzad over 4 years@AshishJain it's
System.Runtime.Serialization