I am writing a wrapper to a REST API. So, whenever I am retrieving items from the server, I just need to play around with the parameters (in the uri). The way I am doing it now works fine but I just feel there must be another elegance way to do this maybe with enum or something.
I don't like that I need to 'know' what are the options are as the Dictionary type is string. I tried with Dictionary<EnumType, string>, but I have more than one type of enum. Plus, I am not sure how to map the EnumType (key) to the appropriate value.
Basically, I am trying to avoid as much as possible the use of magic keyword.
Here is my partial code:
public string GetUnreadItems()
{
var options = new Dictionary<string, string>();
options.Add("ItemType", "Unread");
options.Add("SortBy", "Latest");
// GetItemsBasedOn(options);
}
public string GetAllItems()
{
var options = new Dictionary<string, string>();
options.Add("ItemType", "All");
// GetItemsBasedOn(options);
}
public string GetItemsBasedOn(Dictionary<string, string> options)
{
// Do request here based on options passed
// and return the result to caller function
}
EDIT:
This is what I am trying to implement http://getpocket.com/developer/docs/v3/retrieve
I would like to implement the options sort, detailType, contentType, Favorite, and State. And each of the options have their own options but only one can be selected at a time.
There are a few ways you could go about improving your current design. I don't agree that the solution I am about to present to you is the ideal solution, but given that you have already identified that you would like to use an enum I think you will be content with this solution.
What you can do is define an enum marked with the [Flags] attribute. Assign to each flag in the enum a value that is a power of two. If you want to combine options to create a single option use bitwise or just like I did with the flag named "All" in the proceeding sample:
[Flags]
public enum GetItemOptions
{
Read = 0x1,
Unread = 0x2,
All = 0x1 | 0x2,
SortByOldest = 0x4,
SortByLatest = 0x8
}
From your code sample, the first call will now look like this:
GetItemsBasedOn(GetItemOptions.Unread | GetItemOptions.SortByLatest);
And the second will look like this:
GetItemsBasedOn(GetItemOptions.All);
In order to enable this design you will need to adjust your GetItemsBasedOn method signature so that it specifies an argument of the GetItemOptions enum type. Below is an example of how you can handle different settings.
public static void GetItemsBasedOn(GetItemOptions getItemOption)
{
if (getItemOption.HasFlag(GetItemOptions.SortByOldest) && getItemOption.HasFlag(GetItemOptions.SortByLatest))
throw new ArgumentException("I can't sort by both...");
if (getItemOption.HasFlag(GetItemOptions.Read))
{
Console.WriteLine("READ");
}
if (getItemOption.HasFlag(GetItemOptions.Unread))
{
Console.WriteLine("UNREAD");
}
if (getItemOption.HasFlag(GetItemOptions.SortByOldest))
{
Console.WriteLine("SORT BY OLDEST");
}
else if (getItemOption.HasFlag(GetItemOptions.SortByLatest))
{
Console.WriteLine("SORT BY NLATEST");
}
}
I don't think you know much about bit-wise operations, and for that reason I simplified the code sample as much as possible by utilizing the Enum.HasFlag method which simply checks if the given GetItemOptions enum has a flag specified.
You may have bared witness to this pattern before when using RegexOptions Enumeration or ControlStyles Enumeration
Update
I would suggest that you create an enum for each parameter and define a class like this:
public class PocketDataRequest
{
public State? State { get; set; }
public Favourite? Favourite { get; set; }
public ContentType? ContentType { get; set; }
public Sort? Sort { get; set; }
public DetailType? DetailType { get; set; }
public Dictionary<string, string> ToPostData()
{
return GetType().GetProperties()
.Where(p => p.GetValue(this, null) != null)
.ToDictionary(p => p.Name,
p => p.GetValue(this, null).ToString());
}
}
This would leverage the following syntax:
PocketDataRequest pocketDataRequest = new PocketDataRequest();
pocketDataRequest.State = State.Unread;
pocketDataRequest.Sort = Sort.Newest;
GetItemsBasedOn(pocketDataRequest.ToPostData());
In my implementations ToPostData method, I use LINQ and Reflection, that is just because I am lazy. You need to manually evaluate each enum value, especially if you want to change the enum names to something more appropriate. Also, my code will fail if you try and pass the parameter titled favorite. This is because favorite takes either the number "0" or "1". This is not a big problem because what you can do it define the enum like this:
public enum Favourite
{
UnfavouritedItems = 0,
FavouritedItems = 1
}
and then simply cast the value (Int32) and add that value to the Dictionary<string, string> or NameValueCollection.
Related
First off: Sorry if the question is oddly phrased. I'm new to multiclassing in C#, and I am somewhat stuck.
I am currently making an inventory system that uses one dictionary for all the items. The items themselves are of different classes, and use interfaces for properties. Let's say that these are the interfaces, for simplicity. One interface has the name, the second has a specific value, and the third has yet another specific value.
I can't seem to figure out how (if possible) I can access properties of the second interface, as the only suggestions I get are those of the itemtype used in the dictionary.
// the interface examples
interface IStandardProperties
{
string Name { get; set; }
}
interface IItemType1
{
int SomeValue { get; set; }
}
interface IItemType2
{
int AnotherValue { get; set; }
}
// Then we have two classes that uses these.
class ItemType1 : IStandardProperties, IItemType1
{
public string Name;
public int SomeValue;
public ItemType1()
{
this.Name = "Item type 1"; this.SomeValue = "10";
}
}
class ItemType2 : IStandardProperties, IItemtype2
{
public string Name;
public int SomeValue;
public ItemType1()
{
this.Name = "Item type 1";
this.AnotherValue = "100";
}
}
// and finally the dictionary in question.
Dictionary<int, IStandardProperties> items = New Dictionary<int, IStandardProperties>();
Now, both these items can be stored in the dictionary, however I can't seem to figure out how (or if it's possible) to access the value stored in the interface properties of SomeValue and AnotherValue through the dictionary. I have seen a couple of examples where "as InterfaceName" is used, but I am uncertain of the useage of this.
Is there a way of accessing these? (and in case I am just horribly mistaken about interfaces, are these values even stored in the dictionary?)
I am not in any way an expert, so I would love any corrections or assistance you could provide in this matter.
As you create a Dictionary<int, IStandardProperties>, the only thing we know for sure is that every item implements that specific interface.
If you were to ask the AnotherValue property of an item of type ItemType1, you would obviously not be doing something that's right. This is why your dictionary items cannot show this property: they are not properties of each and every element of your dictionary.
A way you could achieve what you want is type check:
if (items[0] is IItemType1) {
(items[0] as IItemType1).SomeValue ...
}
if (items[0] is IItemType2) {
(items[0] as IItemType2).AnotherValue ...
}
This will check if the item implements said interface, and only then access the member (property) of that interface
If I understand correctly your question, this line
class ItemType1 : IStandardProperties, IItemType1
declares ItemType1 as implementing IStandardProperties and IItemType1, which means that it has both traits.
Your dicationary declaration
Dictionary<int, IStandardProperties> items = New Dictionary<int, IStandardProperties>();
says that your dictionary is typed from int to IStandardProperties. Which means that the value of the dictionary is known and enforced to be of type IStandardProperties.
However, this does not tell about how possible traits of your value.
Therefore, you have to ask for specific trait when you need it (note, as of C# 7 there are shortcuts, which I avoided on purpose):
IStandardProperties v;
if (items.TryGetValue("key", out v))
{
// found. the line below asks if the interface is supported
var item1 = v as IItemType1;
if (item1 != null)
{
// v supports IItemType1, therefore you can do something with it, by using item1
}
// we repeat for IItemType2
var item2 = v as IItemType2;
if (item2 != null)
{
// v supports IItemType2, therefore you can do something with it, by using item2
}
}
else
{
// not found
}
I have enum:
enum MyEnum{
aaaVal1,
aaaVal2,
aaaVal3,
}
I need to have abbreviated version of 'MyEnum' which maps every item from 'MyEnum' to different values. My current approach is method which simply translates every item:
string translate(MyEnum myEnum)
{
string result = "";
switch ((int)myEnum)
{
0: result = "abc";
1: result = "dft";
default: result = "fsdfds"
}
return result;
}
the problem with this approach is that every time programmer changes MyEnum he should also change translate method.
This is not a good way of programming.
So..
Is there any more elegant solution for this problem?
Thank you :-)
Four options:
Decorate your enum values with attributes, e.g.
enum MyEnum
{
[Description("abc")]
AaaVal1,
[Description("dft")]
AaaVal2,
AaaVal3,
}
Then you can create a mapping (like the dictionary solution below) via reflection.
Keep the switch statement but switch on the enum value instead of a number for better readability:
switch (myEnum)
{
case MyEnum.AaaVal1: return "abc";
case MyEnum.AaaVal2: return "dft";
default: return "fsdfds";
}
Create a Dictionary<MyEnum, string>:
private static Dictionary<MyEnum, string> EnumDescriptions =
new Dictionary<MyEnum, string>
{
{ MyEnum.AaaVal1, "abc" },
{ MyEnum.AaaVal2, "dft" },
};
You'd need to handle the defaulting in the method, of course.
Use a resource file, with an entry for each string representation. This would be better if you're really trying to translate in a way that might need different translations for different cultures.
Considering that the use of descriptors on enums is quite common, here it's a good-enough class to do it:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
class EnumDescriptor : Attribute
{
public readonly string Description;
public EnumDescriptor(string description)
{
this.Description = description;
}
public static string GetFromValue<T>(T value) where T : struct
{
var type = typeof(T);
var memInfo = type.GetField(value.ToString());
var attributes = memInfo.GetCustomAttributes(typeof(EnumDescriptor), false);
if (attributes.Length == 0)
{
return null;
}
return ((EnumDescriptor)attributes[0]).Description;
}
}
enum MyEnum
{
[EnumDescriptor("Hello")]
aaaVal1,
aaaVal2,
aaaVal3,
}
string translate(MyEnum myEnum)
{
// The ?? operator returns the left value unless the lv is null,
// if it's null it returns the right value.
string result = EnumDescriptor.GetFromValue(myEnum) ?? "fsdfds";
return result;
}
I'm finding what you're trying to do a bit weird.
If you're making translations, then you should create a RESX file and create ACTUAL translations.
But to answer your question, I guess you could create another enum with the same amount of fields and same numbering (if you're using anything other than the default) and have that act as the abbreviated names. Connecting one to the other should be straightforward:
string GetAbbreviation(Enum1 enum1)
{
return ((Enum2)((int)enum1)).ToString();
}
Attributes will be nice solution for this case. You can specify translations for enumeration members via declarative way:
public class TranslateAttribute
{
public string Translation { get; private set; }
public TranslateAttribute(string translation)
{
Translation = translation;
}
}
enum MyEnum
{
[Translate("abc")]
aaaVal1,
[Translate("dft")]
aaaVal2,
[Translate("fsdfds")]
aaaVal3
}
After this you should write common method for obtaining translations. It should check attribute with translation (via reflection) and return translation if it was specified and default value in other cases.
If I want to restrict the values of the spicelevel column in the database to 1, 2 and 3, I could do something like
private enum SpiceLevel
{
Low=1,
Medium=2,
Hot=3
}
Then in the code I could do (int)SpiceLevel.Low to pick 1 as the spice level.
Now what if I have a need where I can only accept "Red Rose","White Rose" and "Black Rose" for the values of a column in the database? What is a graceful way to handle this?
I am thinking of storing them in a config file or constants, but neither is as graceful as enums. Any ideas?
Update:
The answer here worked for me
You can use a property for this
public string[] AllowedRoses = new string[] { "Red Rose", "White Rose" ,"Black Rose" };
string _Rose = "Red Rose";
public string Rose
{
get
{
return _Rose;
}
set
{
if (!AllowedRoses.Any(x => x == value))
throw new ArgumentException("Not valid rose");
_Rose = value;
}
}
I can see the following options:
verify the value in the setter (see for example l4V's answer)
conceptually, you're thinking about an enum. So you could do the following:
enum RoseType { RedRose, WhiteRose, BlackRose };
and then provide appropriate conversion from this enum to string. Two convenient options how to do it are described here: Enum ToString with user friendly strings. One is to use a custom Description attribute, and the second (I'd prefer this one) to provide an extension method:
public static class RoseTypeExtensions
{
public static string GetString(this RoseType #this)
{
switch (#this)
{
case RoseType.RedRose:
return "Red Rose";
case RoseType.WhiteRose:
return "White Rose";
case RoseType.BlackRose:
return "Black Rose";
default:
throw new InvalidOperationException();
}
}
}
create a set of constants:
public class RoseType
{
public readonly RoseType RedRose = new RoseType("Red Rose");
public readonly RoseType WhiteRose = new RoseType("White Rose");
public readonly RoseType BlackRose = new RoseType("Black Rose");
public string Content { get; private set; }
private RoseType(string content)
{
this.Content = content;
}
public override string ToString()
{
return this.Content;
}
}
As Oskar Berggren correctly pointed out in the comment, RoseType should also provide other standard overrides beside ToString: Equals, GetHashCode, operator== and operator!=.
There is no really good solution. All of them require the database to be "synchronized" with the enum in C#.
Simplest solution:
What you said store the enum values as integers in the database.
Almost as simple but less efficient:
Store the values as strings in the database and convert between string and enum with anEnumVar.ToString() and Enum.Parse (or any of the other parse methods in Enum).
Complex but flexible:
Have a sort of enum in the database: a table with string values and ids and then use foreign keys to that table where you want to save the enums. This allows you to either select/update/insert using the numeric value or the string value (via a join).
It also maintains integrity as it is not possible to store an integer which has no corresponding enum value.
The downside is the complexity.
Create a mapping of string to enum with Dictionary<string, SpiceLevel> to associate the string to the Enum. Wrap them in a class.
You could also use a Decorator attribute [Name("Red Rose"] Low=1, and get that from the enum itself, but that involves reflection, which has some performance issues, especially when iterating through enum values to find the one with the matching attribute.
public static class Spice
{
public enum Level
{
Low = 1,
Medium = 2,
Hot = 3
}
private static readonly Dictionary<string, Level> spices = new Dictionary<string, Level>{
{ "Red Rose", Level.Low },
{ "White Rose", Level.Medium },
{ "Black Rose", Level.Hot },
};
public static bool TryGet(string spiceName, out Level spiceLevel) => spices.TryGetValue(spiceName, out spiceLevel);
public static string SpiceName(Level target) => Enum.GetName(typeof(Spice.Level), target);
}
/// <summary>
/// Some tests to validate it works. This could be a unit test or just in a console app
/// </summary>
public class SpiceTest
{
public void VerifyBlackRoseIsHot()
{
string subject = "Black Rose";
Spice.Level expectedSpice;
// Here's the ease of use. Pass a string, get an enum and whether it's a valid string
var result = Spice.TryGet(subject, out expectedSpice);
//Some Assertion from a unit test library
Assert.True(result, $"Unable to find spice '{subject}', when it should exist");
Assert.True(Spice.Level.Hot.Equals(expectedSpice), $"The returned spice '{ Spice.SpiceName(expectedSpice) }' was not the value 'Hot' as expected");
}
}
I have a factory method that returns the correct sub class depending on three enum values.
One way to do is, would be to use switches in switches in switches. Obviously, I don't like that option very much.
I thought that another option would be to use attributes in C#. Every sub class would have an attribute with that 3 enum values and in the factory I would only have to get the class that has the same enum values corresponding to the enum values i have in the factory.
However, I am quite new to attributes and I did not find any suitable solution in the web. If anyone, could just give me some hints or some lines of code, I really would appreciate that!
First of all, declare your attribute and add it to your classes.
enum MyEnum
{
Undefined,
Set,
Reset
}
class MyEnumAttribute : Attribute
{
public MyEnumAttribute(MyEnum value)
{
Value = value;
}
public MyEnum Value { get; private set; }
}
[MyEnum(MyEnum.Reset)]
class ResetClass
{
}
[MyEnum(MyEnum.Set)]
class SetClass
{
}
[MyEnum(MyEnum.Undefined)]
class UndefinedClass
{
}
Then, you can use this code to create a dictionary with your enums and types, and dynamically create a type.
//Populate a dictionary with Reflection
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new {t, Attribute = t.GetCustomAttribute(typeof (MyEnumAttribute))}).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value, e => e.t);
//Assume that you dynamically want an instance of ResetClass
var wanted = MyEnum.Reset;
var instance = Activator.CreateInstance(dictionary[wanted]);
//The biggest downside is that instance will be of type object.
//My solution in this case was making each of those classes implement
//an interface or derive from a base class, so that their signatures
//would remain the same, but their behaviors would differ.
As you can probably notice, calling Activator.CreateInstance is not performant. Therefore, if you want to improve the performance a little bit, you can change the dictionary to Dictionary<MyEnum,Func<object>> and instead of adding types as values you would add functions wrapping the constructor of each of your classes and returning them as objects.
EDIT: I'm adding a ConstructorFactory class, adapted from this page.
static class ConstructorFactory
{
static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
var paramsInfo = ctor.GetParameters();
var param = Expression.Parameter(typeof(object[]), "args");
var argsExp = new Expression[paramsInfo.Length];
for (var i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
var paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
var newExp = Expression.New(ctor, argsExp);
var lambda = Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);
var compiled = (ObjectActivator<T>)lambda.Compile();
return compiled;
}
public static Func<T> Create<T>(Type destType)
{
var ctor = destType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).First();
Func<ConstructorInfo, object> activatorMethod = GetActivator<Type>;
var method = typeof(ConstructorFactory).GetMethod(activatorMethod.Method.Name, BindingFlags.Static | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(destType);
dynamic activator = generic.Invoke(null, new object[] { ctor });
return () => activator();
}
delegate T ObjectActivator<out T>(params object[] args);
}
You can use it as an alternative to Activator.CreateInstance, it provides greater performance if the result is cached.
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new { t, Attribute = t.GetCustomAttribute(typeof(MyEnumAttribute)) }).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value,
e => ConstructorFactory.Create<object>(e.t));
var wanted = MyEnum.Reset;
var instance = dictionary[wanted]();
Have a look at this article: Creating Custom Attributes. You can then use reflection (for instance GetCustomAttributes) to get the attributes and their values.
Hope this helps
[AttributeUsage(AttributeTargets.Class)]
public class SampleClass : Attribute {
public SampleClass() : base() { }
public SampleClass(YourEnum attributeValue) : this() { MyAttributeProperty = attributeValue; }
public YourEnum MyAttributeProperty { get; set; }
}
public enum YourEnum { Value1, Value2, Value3 }
[SampleClass(YourEnum.Value1)]
public class ExampleValue1Class { }
public class LoadOnlyClassesWithEnumValue1 {
public LoadOnlyClassesWithEnumValue1() {
Type[] allTypes = Assembly.GetExecutingAssembly().GetExportedTypes();
foreach (var type in allTypes) {
if (type.GetCustomAttributes(typeof(SampleClass), false).Length > 0) {
SampleClass theAttribute = type.GetCustomAttributes(typeof(SampleClass), false).Single() as SampleClass;
// this type is using SampleClass - I use .Single() cause I don't expect multiple SampleClass attributes, change ths if you want
// specify true instead of false to get base class attributes as well - i.e. ExampleValue1Class inherits from something else which has a SampleClass attribute
switch (theAttribute.MyAttributeProperty) {
case YourEnum.Value1:
// Do whatever
break;
case YourEnum.Value2:
// you want
break;
case YourEnum.Value3:
default:
// in your switch here
// You'll find the ExampleValue1Class object should hit the Value1 switch
break;
}
}
}
}
}
This way you can specify your enum as a parameter to the attribute. In essence, this is a very simple and lightweight DI container.
I'd suggest for anything more complex, to use something like StructureMap or NInject.
Another solution would be to use Dependency Injection (DI) container. For instance using Unity DI you can:
// Register a named type mapping
myContainer.RegisterType<IMyObject, MyRealObject1>(MyEnum.Value1.ToString());
myContainer.RegisterType<IMyObject, MyRealObject2>(MyEnum.Value2.ToString());
myContainer.RegisterType<IMyObject, MyRealObject3>(MyEnum.Value3.ToString());
// Following code will return a new instance of MyRealObject1
var mySubclass = myContainer.Resolve<IMyObject>(myEnum.Value1.ToString());
Examples on using Unity:
Implementing the Microsoft Unity (Dependency Injection) Design Pattern
Of course you can use any DI container (Castle Windsor, StructureMap, Ninject. Here is a list some of the available .NET DI containers List of .NET Dependency Injection Containers (IOC)
It is possible to use attributes to hold the information, but ultimately the decision process will still have to be made and will likely not be much different; just with the added complexity of the attributes. The nature of the decision remains the same regardless of where you get the information to make the decision, from the existing three enumerations or from attributes.
It may prove more fruitful to look for a way to combine the three enumerations.
Enums can be any integral type, so the easiest way to eliminate nested (and redundant) switches is to combine the enumerations together. This is easiest if the enumeration is a collection of flag values. That is, each value of the enumeration has the value of a single bit in a binary string (1 for the first bit, 2 for the second bit, 4 for the third, 8, 16 and so on).
Provided the values of each of the enumerations can be joined together it reduces the selection process to a single switch statement. This may be best done by concatenating, multiplying or adding the enumeration values -- but how they are joined together depends on the enumerations, and without knowing more details it is hard to provide more definite direction.
I usually access enum description for a corresponding value like:
Enum.GetName(typeof(MyEnum), myid);
I need to have an enum that could use any chars like "hello world %^$£%&"
I've seen people attaching an attribute and adding extensions like here:
http://weblogs.asp.net/stefansedich/archive/2008/03/12/enum-with-string-values-in-c.aspx
but I can't work out if this can be used to access the long description.
Anyone done anything similar?
Thanks
Davy
Why can't it work out?
You can create your own attribute by inherting from Attribute
public class EnumInformation: Attribute
{
public string LongDescription { get; set; }
public string ShortDescription { get; set; }
}
public static string GetLongDescription(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
EnumInformation [] attribs = fieldInfo.GetCustomAttributes(
typeof(EnumInformation ), false) as EnumInformation [];
// Return the first if there was a match.
return attribs != null && attribs.Length > 0 ? attribs[0].LongDescription : null;
}
public static string GetShortDescription(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
EnumInformation [] attribs = fieldInfo.GetCustomAttributes(
typeof(EnumInformation ), false) as EnumInformation [];
// Return the first if there was a match.
return attribs != null && attribs.Length > 0 ? attribs[0].ShortDescription : null;
}
Your Enum would look like this
public enum MyEnum
{
[EnumInformation(LongDescription="This is the Number 1", ShortDescription= "1")]
One,
[EnumInformation(LongDescription = "This is the Number Two", ShortDescription = "2")]
Two
}
You can use it this way
MyEnum test1 = MyEnum.One;
Console.WriteLine("test1.GetLongDescription = {0}", test1.GetLongDescription());
Console.WriteLine("test1.GetShortDescription = {0}", test1.GetShortDescription());
It outputs
test1.GetLongDescription = This is the Number 1
test1.GetShortDescription = 1
You can actually add properties to the attribute to have all kinds of information. Then you could support the localization you are looking for.
What do you mean by "long description"? I've got a library which allows you to attach Description attributes to enum values and fetch them:
public enum Foo
{
[Description("This is a really nice piece of text")]
FirstValue,
[Description("Short but sweet")]
Second,
}
If you're talking about the XML documentation, that's a different matter - that doesn't get built into the binary, so you'd have to build/ship the XML as well, and then fetch it at execution time. That's doable, but I don't have code to do it offhand...
I tend to stay away from this practice. If you think about it, it's binding your code's logic to how you typed your code. It would be much better to use a switch statement, resource file, database, etc...
I learned this the hard way. I had an app that we ultimately decided to obfuscate to help secure our code. As you can imagine, our binaries stopped working the way we wanted due to the enums be renamed during the obfuscation.
If you need an easy way to extract a description attribute for an enum value, have a look at my answer to a similar question
You just need to call the GetDescription extension method on the value :
string description = myEnumValue.GetDescription();
The Unconstrained Melody library mentioned by Jon includes a similar extension method (among many other cool things), you should check it out.