C# Enum Craziness: Sometimes What You Expect Isn’t The Case

January 28, 2008

I learned something new today about enums that I find really weird. Lets start with the following test enum:

public enum Action
{
    Run = 2,
    Walk = 4,
    Crawl = 8
}

and then some code to do something with that enum:

static void Main(string[] args)
{
    Console.WriteLine((Action)2);
    Console.WriteLine((Action)4);
    Console.WriteLine((Action)8);
    Console.WriteLine((Action)10);
}

What do you think will happen here? Will it even compile?

When I saw this code snippet I said to myself, “the first three lines look ok but the last line won’t work because 10 isn’t a valid value for this enum. Well, I was wrong. This program actually outputs:

Run
Walk
Crawl
10

Huh?!? How could this be? 10 isn’t a valid value according to my enum definition!

This Should Never Happen…Right?

Ok, lets try something different. How about a method?

public static void Execute(Action action)
{
    switch (action)
    {
        case Action.Run:
            Console.WriteLine("Running");
            break;
        case Action.Walk:
            Console.WriteLine("Walking");
            break;
        case Action.Crawl:
            Console.WriteLine("Crawling");
            break;
        default:
            Console.WriteLine("This will never happen! {0}", action);
            break;
    }
}

Surely you can’t pass anything into this method other than one of the 3 values defined in my enum. So lets run some code:

static void Main(string[] args)
{
    Execute(Action.Run);
    Execute(Action.Walk);
    Execute((Action)55);
}

What do you think this does? Well, it outputs:

Running
Walking
This will never happen! 55

Just about this time you must be thinking: “This has to be a bug!”. Well, it is not. It is by design. here is the excerpt from the C# design spec:

14.5 Enum values and operations

Each enum type defines a distinct type; an explicit enumeration conversion (Section 6.2.2) is required to convert between an enum type and an integral type, or between two enum types. The set of values that an enum type can take on is not limited by its enum members. In particular, any value of the underlying type of an enum can be cast to the enum type, and is a distinct valid value of that enum type.

Wow, that is not at all what I expected when it comes to limiting the possible values of enums. So what are enums good for then? Are they just for code readability? Between this little revelation and my previous hack to associate string values to enums, I am loosing faith in enums.

Can You Handle it?

So what is the best way to check for this in your methods? Should you throw an exception if you receive an enum value you were not expecting? Should you just ignore it? Well, lets see what the .Net base class libraries do.

First, lets start with the System.IO.File class. What happens if I run the following code?

File.Open(@"C:\temp\test.txt", (FileMode)500);

Well, it throws a System.ArgumentOutOfRangeException with the message “Enum value was out of legal range.”. Ok, makes sense – I did pass in something out of range.

Lets try reflection. What does the following code snippet output?

PropertyInfo[] info = typeof(StringBuilder)
.GetProperties((BindingFlags)303); Console.WriteLine(info.Length);

Well, it just outputs ‘0’ which means in this case it is just being ignored and an empty array is returned.

What about System.String? Lets try this code snippet:

"TestString".Equals("TESTSTRING", (StringComparison)245);

Well, it turns out this throws an exception but instead of being a System.ArgumentOutOfRangeException like System.IO did, it throws a System.ArgumentException with the message “The string comparison type passed in is currently not supported.” Ok, so this is kind of the same but still a little inconsistent if you ask me.

Is Anything Safe These Days?

So what is a developer to do? Obviously you need to be aware of this when you are receiving enum types from publicly facing code. It seems there is no clear guidance on this that I can find. The C# design spec explains the behavior but doesn’t really give any guidance on why or how this should be handled. So the only other place to turn for guidance is one of my favorite .Net books Framework Design Guidelines by Brad Abrams and Krzysztof Cwalina. On their section on enums, I can’t find any guidance on how to handle out of range enum values. I do, however, find guidance that we should be using enums:

DO use an enum to strongly type parameters, properties, and return values that represent sets of values

They also suggest that enums should be favored over static constants:

DO favor using an enum over static constants

And Jeffrey Richter (and while I am pointing out my favorite .Net books, I have to add Mr. Richter’s book CLR via C# which contains priceless information on the CLR that you can’t find anywhere else) adds the following commentary:

An enum is a structure with a set of static constants. The reason to follow this guideline is because you will get some additional compiler and reflection support if you define an enum versus manually defining a structure with static constants.

So I guess we do continue to use enums and just know that we can’t always trust their values to be valid. Do you think the C# design spec should be amended to include a recommended behavior for out of range enum values? Perhaps Brad and Krzysztof can include something in their second edition of Framework Design Guidelines.

kick it on DotNetKicks.com


Associating Strings with enums in C#

January 17, 2008

I have seen other great articles out lining the benefits of some pretty clever and useful helper classes for enums. Many of these methods almost exactly mirror methods I had written in my own EnumHelper class. (Isn’t it crazy when you imagine how much code duplication there must be like this out there!)

One thing that I don’t see emphasized much is trying to associated string values with enums. For example, what if you want to have a Drop Down list that you can choose from a list of values (which are backed by an enum)? Lets start with a test enum:

public enum States
{
    California,
    NewMexico,
    NewYork,
    SouthCarolina,
    Tennessee,
    Washington
}

So if you made a drop down list out of this enum, using the ToString() method, you would get a drop down that looks like this:

image

While most people will understand this, it should really be displayed like this:

image

“But enums can’t have spaces in C#!” you say. Well, I like to use the System.ComponentModel.DescriptionAttribute to add a more friendly description to the enum values. The example enum can be rewritten like this:

public enum States
{
    California,
    [Description("New Mexico")]
    NewMexico,
    [Description("New York")]
    NewYork,
    [Description("South Carolina")]
    SouthCarolina,
    Tennessee,
    Washington
}

Notice that I do not put descriptions on items where the ToString() version of that item displays just fine.

How Do We Get To the Description?

Good question! Well, using reflection of course! Here is what the code looks like:

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();
}

This method first looks for the presence of a DescriptionAttribute and if it doesn’t find one, it just returns the ToString() of the value passed in. So

GetEnumDescription(States.NewMexico);

returns the string “New Mexico”.

A Free Bonus: How to Enumerate Enums

Ok, so now we know how to get the string value of an enum. But as a free bonus, I also have a helper method that allows you to enumerate all the values of a given enum. This will allow you to easily create a drop down list based on an enum. Here is the code for that method:

public static IEnumerable<T> EnumToList<T>()
{
    Type enumType = typeof(T);

    // Can't use generic type constraints on value types,
    // so have to do check like this
    if (enumType.BaseType != typeof(Enum))
        throw new ArgumentException("T must be of type System.Enum");

    Array enumValArray = Enum.GetValues(enumType);
    List<T> enumValList = new List<T>(enumValArray.Length);

    foreach (int val in enumValArray)
    {
        enumValList.Add((T)Enum.Parse(enumType, val.ToString()));
    }

    return enumValList;
}

As you can see, the code for either of these methods isn’t too complicated. But used in conjunction, they can be really useful. Here is an example of how we would create the drop down list pictured above based on our enum:

DropDownList stateDropDown = new DropDownList();
foreach (States state in EnumToList<States>())
{
    stateDropDown.Items.Add(GetEnumDescription(state));
}

Pretty simple huh? I hope you find this as useful as I do.

One More Example

There is one more scenario that I often find myself needing to associate string values with enums – when dealing with legacy constant string based system. Lets say you have a library that has the following method:

public void ExecuteAction(int value, string actionType)
{
    if (actionType == "DELETE")
        Delete();
    else if (actionType == "UPDATE")
        Update();
}

(I tried to make this look as legacy as I could for a contrived example). What happens if somebody passes in “MyEvilAction” as a value for actionType? Well, whenever I see hard coded strings, that is a code smell that could possibly point to the use of enums instead. But sometimes you don’t have control over legacy code and you have to deal with it. So you could make an enum which looks like this:

public enum ActionType
{
    [Description("DELETE")]
    Delete,
    [Description("UPDATE")]
    Update
}

(I know, I know, this is a very contrived example) Then you could call the ExecuteAction Method like this:

ExecuteAction(5, GetEnumDescription(ActionType.Delete));

This at least makes the code more readable and may also make it more consistent and secure.

kick it on DotNetKicks.com


Useful Code Snippet: Web Property

January 15, 2008

Write WebControls much? Well, I do and I have a code snippet that I pretty much can’t live without. It is used for creating ViewState backed properties. Here is the basic pattern I use when creating properties for my web controls:

public string Name
{
    get
    {
        object o = ViewState["Name"];
        return o == null ? String.Empty : (string)o;
    }
    set { ViewState["Name"] = value; }
}

Basically, you just want a property (in this case a string named “Name”) and you want to store it in ViewState. And when the value is being retrieved, if it is not in ViewState, you want to retrieve some default value. This is a pattern that I repeat over and over in my controls. So I made a code snippet to make it easier.

I use the shortcut ‘webprop’

image

and it expands like this:

image

To install, you just need to place the .snippet file (link to download below) in your ‘My Snippets’ folder which in windows vista is located at:

C:\Users\<UserName>\Documents\Visual Studio 2005\Code Snippets\Visual C#\My Code Snippets

or if you use Visual Studio 2008:

C:\Users\<UserName>\Documents\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets

I hope this is helpful. It saves me a bunch of time.

You can download the .snipped file here

kick it on DotNetKicks.com


Windows Vista Ultimate Extras – Sometimes the Truth Hurts

January 9, 2008

Long Sheng has posted a very humorous and clever post about the lack of Windows Vista Ultimate extras.

http://www.istartedsomething.com/20080109/ultimate-extras-inactive-reminder/

I really respect the way that he states the facts and doesn’t resort to anger. I also love how he has suggestions for possible extras that are very realistic. It is a good practice to always suggest a solution whenever you point out a problem.


I Was Given the Gift of Smugmug Customer Service

December 31, 2007

In my previous post, I outlined a little trouble I ran into trying to purchase a friend a Smugmug account as a gift. Well, I am happy to report that the folks at Smugmug responded amazingly and have managed to show how much they care about their customers (as well as potential customers)…I guess there is a reason why they refer to their support personal as “Support Heroes”.

The Man Himself

If you look at the comments for my previous post, you will notice the first comment is from none other than the founder, CEO and Chief Geek at SmugMug – Don MacAskill. I love it when leaders of companies care enough about their company that they are willing to step up and participate in the conversation about their company on the Internet. There are a couple of things Don said in his comment that I think explain exactly why I even wrote the first post in the first place:

I’m so glad you spoke up about it rather than just shrugging and going somewhere else

It is usually way easier to just shrug something off. In fact, I was ready to do that and just buy my friend a Flickr account as a gift. But, my wife was persistent about at least seeing the Smugmug thing through and I figured I wasn’t the only one who had experienced this problem. This is a key point for users of any software: If you are confused about something or are experiencing any type of difficulty, chances are you are not alone. It is too easy for users to blame themselves.

without feedback like this, we’d never improve, so I’m glad to hear it.

Smugmug is obviously a company that wants to improve their product any way they can. One reason why I love Don’s stance on this issue so much, is that I now how hard it is to accept feedback on something you feel so passionate about. Smugmug is a family owned business that Don MacAskill started with his father and he could have just have easily been defensive or taken feedback personally. You’d be surprised how many CEOs react like that. And don’t get me started on developers being defensive about their code. Feedback is good. Wouldn’t your rather hear what your actual users think rather than just guessing what they must think?

Above and Beyond

Well, in the end I was able to give the gift of Smugmug as well as receive a gift because the folks at Smugmug decided to give me and my friend free accounts as a way to show how much they care about any difficulty I have experienced. That is more then I would have ever wanted to come out of this situation. They didn’t have to do that. But they did. And that is why they have renewed my faith in how much they care about their customers.


Why Won’t You Let Me Give the Gift of Smugmug?

December 29, 2007

Ok, so here is the story. I have some friends that are having a baby soon so I thought a good Christmas gift to give them would be a subscription to a photo sharing web site so they could share all their photos of them and their new child. Since I have a Flickr pro account and love it, I figured I would get them a Flickr account. But then I read about Robert Scoble raving about how much he loves Smugmug and that he is possibly moving from Flickr to Smugmug. So I decided to give Smugmug a try.

On Trial

So I signed up for a trial account with Smugmug and just browsed around to get a general feel for the site. I really like the site and they have a done a wonderful job of making it easy to perform most of the common tasks that a photo sharing site should enable you to do.

I talked it over with my wife and we both agreed that Flickr is more techy while Smugmug is more family friendly. Since we wanted a site which would allow our friends to share baby photos with their family, Smugmug seemed like a really good choice.

A Snafu

So I searched around the Smugmug site and finally found a page where you can “give the gift of Smugmug” so I decided I would go ahead with that. One problem though, when I reached the gifting page, I was greeted with a blank page. Hmmm. That’s strange. Maybe it is my browser. So I tried it in Firefox. Same thing. Try it for yourself, here is the Url:

https://www.smugmug.com/gift.mg

Then, I remembered that Smugmug is a family owned business and they boast that they have really personal and friendly support. So I wrote those wonderful humans at help@smugmug.com.

Warm, but not very helpful

I wrote support and explained that I was getting a blank page in both browsers when trying to give the gift of Smugmug. I received a response a couple of days* later that basically consisted of the usual support response: Clear your browser cache, delete all of your cookies, and restart your computer. Ok, that is to be expected. It seems that in technical support you have to start with the most basic things first. I knew it wouldn’t help but I decided to try it anyway. Well, it didn’t help. I was still getting a blank page.

*Update: After going back and checking the timestamps on the emails with Smugmug support, the response actually came the next day and from then on out they responded to all of my emails within a couple of hours except for my very last message to them which was never responded to.

Next, I tried it at a different computer (from work) and again, in both browsers. Same results. So I replied to support and told them this and asked if they had any other ideas. The response I received really puzzled me:

Thanks for contacting SmugMug. To give the ‘Gift of SmugMug’ you must
have a current / active account with us and have credit card information
in the control panel of your account. Check to make sure you have
updates your account billing information.

Well, I guess I don’t mind giving them my credit card information since I will need to be paying for this gift. So I went to my user settings on Smugmug and went to update my credit card information. Well, in order to enter credit card information, I must sign up for my own Smugmug account and pay for it. Ok, so let me get this straight. To give somebody else a gift, I must fist purchase an account for myself? But I am perfectly happy with my Flickr account and I don’t need to pay another fee for a site I may or may not use.

In A Tight Spot

So now here I am, three days after Christmas and I still have not been able to purchase a Christmas gift for my friends. My first reaction was to just back out and give them a Flickr account. But my wife insisted we get them a Smugmug account – it is prettier. So what do I do? At this point I don’t feel like I am getting much help from Smugmug. I am trying to give them money and they won’t take it.

Why Blank?

Ok, so maybe they haven’t really set up a way for non-members to give others gifts. Maybe this is even a business rule they decided to enforce on their web site. But why not explain this on the page rather than just giving me nothing? Here is what the code for that page must look like:

if(User.IsPayingCustomer)
{
     DisplayGiftForm();
}
else
{
     DisplayBlankPage();
}

Makes no sense to me. I must be missing something.


You Know You Are An Influential Blogger When…

December 13, 2007

Sometimes it is hard to see threads of discussions in blog land because you may only be reading a subset of the blogs involved in the discussion. In this case, I just happened to be subscribed to many of the blogs in this thread. First let me lay out the timeline of posts:

Jeff Atwood published his post Sorting for Humans : Natural Sort Order

Ian Griffiths responds with post entitled Natural Sorting in C#

Charles Petzold responds with Sorting Without Spaces

Dare Obasanjo responds with his post Natural Sort in IronPython vs. C# 2.0

Now these are some pretty big names to have both reading your blog and responding on their own blog. And according to technorati, there are 9 blog reactions to Jeff’s post. That is pretty impressive. That makes Jeff Atwood a very influential blogger in my book.

If this were my timeline, it would look more like this:

Luke published his post on Asp.Net Control For Google Charts

Luke’s Mom emails him and says, "I read your new blog post and I didn’t understand a word you said but great job!"

Luke’s Wife calls him and says, "Your Mom really likes your new blog post."

Trackback spam responds to Luke’s post: "Want to buy some ViAGra?"