Inconsistencies in the .NET Enum class

During a recent project of mine, I had to do a lot of enum manipulation using the .NET Enum class and I have to say I wasn’t impressed. Besides the shortcoming of it not being a generic class (and thus not being especially type-safe), Enum also has some strange inconsistencies in terms of how it handles matched integral types.


Why does GetName return null for any integral type you pass it except those that correspond to a constant?

For example, this is completely valid:

enum Fruit : byte { Apple, Orange, Cumquat };
var fruit = Enum.GetName( typeof(Fruit), ulong.MaxValue );
// fruit now equals null

In every other case in the Enum class where you pass an integral value outside the range of the underlying type, you get an exception. Except here.


Why does IsDefined throw an exception when you pass it an integral value that can be safely narrowed to the enumeration’s underlying type?

For example, this will throw an exception:

enum Fruit : byte { Apple, Orange, Cumquat };
var defined = Enum.IsDefined( typeof(Fruit), 0 );

Why? Because it’s a integer literal (and therefore type int) and the underlying type of Fruit is byte. This would be alright if this is how the Enum class consistently treated this case, but it’s not. In every other method, the Enum class is OK with you passing in an int value for a byte enumeration (as long as it’s within the range of the underlying type).


Why does ToObject silently overflow for values outside the range of the enumeration’s underlying type?

For example, this code will give the following non-intuitive result:

enum Fruit : byte { Apple, Orange, Cumquat };
var apple = Enum.ToObject( typeof(Fruit), 0 );
var elppa = Enum.ToObject( typeof(Fruit), 256 );
Assert.AreEqual(apple, elppa);

Assuming that we ignore the fact that silently overflowing is typically a bad idea, this is again completely inconsistent with the rest of the library. Why overflow here, but not in GetName?


The .NET Enum class is not lacking in it’s ability to extract any information you need from an enumeration. It is, however, a little inconsistent in terms of how it treats underlying type mismatches, overflows and narrowing conversions. Barring a new, generified Enum class from Microsoft, the best way to deal with these inconsistencies is to either be aware of them, or use a third-party library to hide them.

(Edit: Some people have noted that my conclusion was a bit weak and preachy towards Dnum, which I have to admit is not without truth. I’ve seen edited it. For the record, the old conclusion was: “Fortunately, these and other problems have been fixed in my Dnum library, which should be released in the next couple days. Be sure to check it out.”).

6 Comments so far

  1. on September 14th, 2009

    Inconsistencies in the .NET Enum class…

    You’ve been kicked (a good thing) – Trackback from…

  2. kev on September 14th, 2009

    Really interesting Cam. Any idea why these inconsistencies exist? Is it some restriction with the CLR or some language nuance? Will your fix have any drawbacks such as speed/performance? Looking forward to the official release!

  3. path on September 14th, 2009

    This is probably besides the point, but in general enums are probably not even worth using. In general being able to switch back and forth between enums and int’s isn’t really a good thing. But the issue is deeper than that. Enum’s don’t allow you to add logic in, so invariably once a system starts with enums it seems to evolve down the path of switching on the value of something or branching. It seems far better to just create an abstract class and a bunch of derived class (maybe single instances of each) and push logic into them.

  4. agreed on September 14th, 2009

    I agree with path. You can create something far better than an enum using classes.

  5. BK on September 15th, 2009

    Good post. I didn’t realize all those inconsistencies existed..

    BTW, instead of using the underlying mappings with their inconsistencies, have a look at my enum framework post– the framework allows you to tag enum fields using attributes of arbitrary type and parse enums with many-to-many relationships.

  6. Twitted by tek_news on September 21st, 2009

    […] This post was Twitted by tek_news […]

Leave a reply