Monday, November 29, 2010

Casting Enums

I had to think hard today on how to cast back to an Enum from an int using Reflection, so seems like a good topic to recap on. If you know what you want to cast it to thats easy, just cast it, but what if you have an instance of Type and you want to cast it to that type?

I think everyone knows that enums are based on integers (32 bit or 64 bit), and sometimes it makes sense to use flag enums where each individual bit in a series of bytes represents one element of the enum. Effectively allowing an enum value to represent two or more values simultaneously.

Why do you need to cast enums to ints or strings occasionally? Sometimes this is necessary for persistence (to database or other long term storage mechanism) or communication serialisation reasons.
In these examples I'll use this enum (generally for a non-flags enum you do not set the values): 

public enum SomeFlags { Default = 4096, Email = 16384, Mobile = 32768, LandLine = 8192, Fax = 1, }

To and From Strings

SomeFlags x = SomeFlags.Email;
string str = x.ToString();
Variable str will now equal "Email".

SomeFlags x = (SomeFlags)Enum.Parse(typeof(SomeFlags), "Email");
Variable x will now be of type SomeFlags and set to value SomeFlags.Email. As you can see this method creates a rather bad dependency on those string enum names never changing.

Don't rely on Enum.GetName(Type, String) this will only work if there is an exact match.  If you are using a Flags enum and it is set to two or more values simultaneously (ie using a binary OR) this method  will not work.

To and From Integers
SomeFlags x = SomeFlags.Email; 
int value1 = (int)x;
Variable value1 is now equal to 16384.

int y = 16384;
SomeFlags x = (SomeFlags)Enum.ToObject(typeof(SomeFlags), y);
Variable x is now of type SomeFlags and is set to SomeFlags.Email.

Same comment as above applies here do not rely on Enum.GetName(Type, Int) this will not work for flag enums when they are set to two or more values simultaneously using a binary OR.

Other Casting
There is also a EnumConverter class, but you should never directly create this class. Rather call the GetConverter static method of the TypeDescriptor class. This converter is designed to handle the internals of how to convert to and from strings.

See Also
Don't forget about the other handy conversions available on the Convert static class. Especially the dynamic runtime convert Convert.ChangeType(destinationType, object).

1 comment:

  1. Note that the Enum.ToObject(...) method allows you to cast a value that does not exist in an enumeration into the enum type. Ie this code compiles and runs with no exceptions:

    public enum Enum1
    Test = 1,
    Apple = 2,

    public static class Program
    public static void Main(string[] args)
    int value1 = 0;
    int value2 = 1;

    var enum1 = (Enum1)Enum.ToObject(typeof(Enum1), value1);
    var enum2 = (Enum1)Enum.ToObject(typeof(Enum1), value2);

    You'll need to also use the Enum.IsDefined(...) to check all is well.