0

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?

1

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

6 Comments

I am using it to populate a WPF combobox. Could you show me an example of doing something like this with the value converter?
While also being usable by other parts of the code to get the description of the enum field.
I have updated the post to include the converter and an example of it being used.
Ultimately I am trying to accomplish this: stackoverflow.com/questions/58743/… while not negating the GetDescription extension
I was able to do it with the following pastebin.com/s573m1vc and pastebin.com/BcrgtSCC
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.