Reputation: 584
I have an enumeration of enum elements and description attributes
public enum CourseGrades
{
[Description("A")]
A = 11,
[Description("A-")]
AMinus = 10,
[Description("B+")]
BPlus = 9,
[Description("B")]
B = 8,
[Description("B-")]
BMinus = 7,
[Description("C+")]
CPlus = 6,
[Description("C")]
C = 5,
[Description("C-")]
CMinus = 4,
[Description("D+")]
DPlus = 3,
[Description("D")]
D = 2,
[Description("D-")]
DMinus = 1,
[Description("E")]
E = 0,
[Description("Audit")]
AU = -1,
[Description("Incomplete")]
IC = -2,
[Description("Withdrawl")]
WD = -3,
[Description("Not Applicable")]
NA = -4
}
My issue is that I am trying to build a list of the descriptions and I am getting stuck on how to do that. All of the answers I have seen say to use Enum.GetNames()
or Enum.GetValues()
which I know how to do.
The issue with both of those is that they return a string array which has lost all context on where it came from so that I am not able to follow it to get the description for the particular enum value that I want.
The way I get the description right now is to call CourseGrades.A.GetDescription()
because I have an extension method that handles getting the description attribute view code.
I've been hoping to do something like
var elements = System.Enum.GetElements(CourseGrades);
var dict = new Dictionary<CourseGrades, string>();
foreach (var element in elements) {
dict.Add(element, element.GetDescription());
}
but I am beginning to think that something like this isn't possible to do.
I have been trying hard to avoid brute forcing it by doing
private Dictionary<CourseGrades, string> _courseGradesWithCaption = null;
public Dictionary < CourseGrades, string > CourseGradesWithCaptions
{
get
{
if ( _courseGradesWithCaption == null )
_courseGradesWithCaption = new Dictionary < CourseGrades, string > ()
{
{ CourseGrades.A, CourseGrades.A.GetDescription () }
, { CourseGrades.AMinus, CourseGrades.AMinus.GetDescription () }
, { CourseGrades.BPlus, CourseGrades.BPlus.GetDescription () }
// ... snip ...
};
return _courseGradesWithCaption;
}
}
I thought I was getting somewhere by borrowing how the extension method linked above went through the enumeration by doing
public static class EnumerationCaptionsBuilder
{
public static Dictionary < T, string > BuildCaptions<T> ( T e ) where T : IConvertible
{
if (!(e is System.Enum)) throw new ArgumentException("e is expected to be an enumeration.");
var type = e.GetType ();
var values = System.Enum.GetValues ( type );
var dict = new Dictionary<T, string> ();
foreach ( var val in values )
{
if ( (int) val != e.ToInt32 ( CultureInfo.InvariantCulture ) ) continue;
var enumElement = type.GetMember ( type.GetEnumName ( val ) ?? throw new InvalidOperationException ());
dict.Add(enumElement, enumElement.GetDescription());
}
}
}
But that was when I learned that type.GetMember
returns a MemberInfo object which is not what I am looking for.
Is there a way to do what I am wanting to do or am I just barking up an impossible tree?
Upvotes: 0
Views: 320
Reputation: 693
I am not totally following why your extension doesn't work for you (if you have it on the Enum your "requested" code should work).
Here is how I have done this though:
public static class EnumerationExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
public static IEnumerable<TEnum> GetEnumCollection<TEnum>(bool skipFirst = false)
{
var result = new List<TEnum>();
var enums = Enum.GetValues(typeof(TEnum));
for (int i = 0; i < enums.Length; i++)
{
if (skipFirst && i == 0) continue; //Some enums use "Invalid" or "Default" as first value
TEnum e = (TEnum)enums.GetValue(i);
result.Add(e);
}
return result;
}
}
Also, one thing to think about is why are you needing it. If this is for display purposes, perhaps a IValueConverter is what you should do. This allows you to have a collection of enumeration types and then display the description quite easy as the IValueConverter object receives the enum and then returns the .Description extension call.
The example I provided has a "skipFirst" defaulted to false, because often when I make enumerations I put an invalid sate first (e.g. Default, Undefined etc.) to ensure default state is not valid (I want to ensure something is set and not use a default).
EDIT Adding the IValueConverter that I have used.
public class EnumerationToDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var casted = value as Enum;
return casted?.GetDescription();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//we have no need to get from visual descirption to the enumeration at this time.
throw new NotImplementedException();
}
}
Then you just need to instantiate your converter as a resource with a key and reference it.
<converters:EnumerationToDescriptionConverter x:Key="EnumerationToDescriptionConverter" />
<TextBlock Text="{Binding Converter={StaticResource EnumerationToDescriptionConverter}}"/>
In my case the TextBlock is within a DataTemplate used for a ItemsControl that is bound to a collection of the enumerations that are retrieved via the other extension method posted above.
Upvotes: 1