Generic method to display enum value names
Is there a way to display the name of an enum's value? say we have:
enum fuits{
APPLE,
MANGO,
ORANGE,
};
main(){
enum fruits xFruit = MANGO;
...
printf("%s",_PRINT_ENUM_STRING(xFruit));
...
}
using the preprocessor
#define _PRINT_ENUM_STRING(x) #x
won't work as we need to get the value of the variable 'x' and then convert It开发者_如何学C to string. Is this at all possible in c/C++?
You could use the preprocessor to do this, I believe this technique is called X-Macros:
/* fruits.def */
X(APPLE)
X(MANGO)
X(ORANGE)
/* file.c */
enum fruits {
#define X(a) a,
#include "fruits.def"
#undef X
};
const char *fruit_name[] = {
#define X(a) #a,
#include "fruits.def"
#undef X
};
Note that the last entry includes a trailing comma, which is allowed in C99 (but not in C89). If that is a problem you can add sentinal values. It is also possible to make the macro more complicated by giving multiple arguments for custom names or enum values, etc:
X(APPLE, Apple, 2)
#define X(a,b,c) a = c, /* in enum */
#define X(a,b,c) [c] = #b, /* in name array */
Limitations: You cannot have negative constants and your array is sizeof (char *) * largest_constant
. But you could work around both by using an extra lookup table:
int map[] = {
#define X(a,b,c) c,
#include "fruits.def"
#undef X
};
This doesn't work of course. What does work is generating an extra set of enum
constants as keys for the names:
enum fruits {
#define X(a,b,c) a ## _KEY,
#include "fruits.def"
#undef X
#define X(a,b,c) a = c,
#include "fruits.def"
#undef X
};
Now you can find the name of X(PINEAPPLE, Pineapple, -40)
by using fruit_name[PINEAPPLE_KEY]
.
People noted that they didn't like the extra include file. You don't need this extra file, you also use a #define
. This may be more appropriate for small lists:
#define FRUIT_LIST X(APPLE) X(ORANGE)
And replace #include "fruits.def
with FRUIT_LIST
in the previous examples.
You can use a mapping in this case.
char *a[10] = { "APPLE","MANGO","ORANGE"};
printf("%s",a[xFruit]);
Yes the preprocessor won't work unless you provide the exact enum -value.
Also check this question for more insights.
I've used preprocessor programming successfully to get a macro of this kind:
DEFINE_ENUM(Fruits, (Apple)(Mango)(Orange));
It does a tad more than just printing the names, but it could easily be simplified to 2 switches if necessary.
It's based on Boost.Preprocessor facilities (notably BOOST_PP_SEQ_FOREACH
) which is a must have for preprocessor programming, and I find it much more elegant than the X
facility and its file reinclusion system.
public enum LDGoalProgressUpdateState {[Description("Yet To Start")] YetToStart = 1, [Description("In Progress")] InProgress = 2, [Description("Completed")] Completed = 3 } var values = (ENUMList[])Enum.GetValues(typeof(ENUMList)); var query = from name in values select new EnumData//EnumData is a Modal or Entity { ID = (short)name, Name = GetEnumDescription(name)//Description of Particular Enum Name }; return query.ToList();
region HelperMethods
public static string GetEnumDescription(Enum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); if (attributes != null && attributes.Length > 0) return attributes[0].Description; else return value.ToString(); } #endregion
精彩评论