43

This may seem a little upside down faced, but what I want to be able to do is get an enum value from an enum by its Description attribute.

So, if I have an enum declared as follows:

enum Testing
{
    [Description("David Gouge")]
    Dave = 1,
    [Description("Peter Gouge")]
    Pete = 2,
    [Description("Marie Gouge")]
    Ree = 3
}

I'd like to be able to get 2 back by supplying the string "Peter Gouge".

As a starting point, I can iterate through the enum fields and grab the field with the correct attribute:

string descriptionToMatch = "Peter Gouge";
FieldInfo[] fields = typeof(Testing).GetFields();

foreach (FieldInfo field in fields)
{
    if (field.GetCustomAttributes(typeof(DescriptionAttribute), false).Count() > 0)
    {
        if (((DescriptionAttribute)field.GetCustomAttributes(typeof(DescriptionAttribute), false)[0]).Description == descriptionToMatch)
        {

        }
    }
}

But then I'm stuck as to what to do in that inner if. Also not sure if this is the way to go in the first place.

0

3 Answers 3

54

Using the extension method described here :

Testing t = Enum.GetValues(typeof(Testing))
                .Cast<Testing>()
                .FirstOrDefault(v => v.GetDescription() == descriptionToMatch);

If no matching value is found, it will return (Testing)0 (you might want to define a None member in your enum for this value)

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

9 Comments

Ahh, LINQ to the rescue once again. I really like this solution, thanks!
-1: extra objects created in this code: 1) a RuntimeType, 2) a cast-iterator, 3) a lambda object, 4) a WhereIterator. Extra objects created with Ani's solution; none.
Yes, your method does use reflection, look at what you linked to, so you do need to get the FieldInfo. You are not correct about the non-object-ness of the anonymous method (or lambda or whatever) as you are doing a closure capture over "descriptionToMatch" which has to capture its state references privately.
@Henrik, yes, the GetDescription method does use reflection, I forgot that... but it's the only way you can access the attribute anyway. And the closure does generate a new type; I was wrong when I said that it was a method in the same object, I forgot about the closure. It's just the term "lambda object" that bothered me, because I don't think it's accurate, although I understand your meaning now... Anyway, what's so wrong with creating new objects ? Ani's solution doesn't fully answer the question, it only gives the value of a specific enum value...
Not to be nitpicking, but pointing it out if it helps anyone - for your v.GetDescription to work, you should Cast<> to Enum type, not Testing since that's what the GetDescription extension method accepts.
|
5
return field.GetRawConstantValue();

You could of course cast it back to Testing if required.

5 Comments

It looks promising, but it doesn't work. I get an InvalidOperationException : "Operation is not valid due to the current state of the object."
Just had a look in Reflector: the only class that actually implements this method is MdFieldInfo. In RtFieldInfo, it just throws an InvalidOperationException.
It works fine; you have to skip the first result in the enumeration. typeof(Testing).GetFields[1].GetRawConstantValue(); Alternatively, you could filter on type MdFieldInfo as suggested by Thomas. This is probably a better solution.
Indeed... the first field is value__, and it's not actually an enum member
the proper way is to filter the actual GetFields call: typeof(Testing).GetFields(BindingFlags.Public | BindingFlags.Static)
2

Ok, after typing all that I think this is a case of a decision right at the beginning leading me down the wrong path. Enum seemed the right way to go to start with, but a simple Dictionary<string, int> will suffice and be a hell of a lot easier to work with!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.