Tuesday, November 04, 2008

Enum Parse Extension Methods

When I write code I don't like to depend on catching exceptions to control my programming logic, so as much as I can I try to check for nulls, empty, etc...

When parsing one type into another there are usually TryParse() methods available so that an exception does not occur. I've always been a little confused why there wasn't such a method off the Enum class. So, I decided to make my own.

However, after I started to extend the TryParse method off of the Enum, the answer started to become clear why that was not a feature :) I could extend the actual specific enum, but that didn't really help me any. I wanted a Generic solution for all enums.

So, instead of making an Enum.TryParse(), I decided to extend the string class to add string.ToEnum() and string.TryToEnum(). The string is usually the class that I want to parse into a specific Enum after all.

The following is the Extension methods that I created...

using System;

namespace Web.Helpers {
    public static class EnumHelper {
        public static bool TryToEnum<T>(this string obj, out T parsed) {
            bool isParsed = false;

            if (Enum.IsDefined(typeof(T), obj)) {
                parsed = (T)Enum.Parse(typeof(T), obj);
                isParsed = true;
            } else {
                parsed = (T)Enum.Parse(typeof(T), Enum.GetNames(typeof(T))[0]);
            }

            return isParsed;
        }
        
        public static T ToEnum<T>(this string obj) {
            return (T)Enum.Parse(typeof(T), obj);
        }
    }
}

I created a set of 4 MS Unit tests to exercise different scenarios that might exist. Let me know if you see any other tests that I should test.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Web.Helpers;

namespace WebTests.Generic {
    [TestClass]
    public class EnumTest {
        public enum Color { Red, Orange, Yellow, Green, Blue, Indigo, Violet };

        [TestMethod]
        public void TryToEnumWorksWithValidEnum() {
            Color parsedColor = Color.Blue;

            string realColor = "Yellow";
            bool canParse = realColor.TryToEnum<Color>(out parsedColor);
            Assert.AreEqual(true, canParse);          
        }

        [TestMethod]
        public void TryToEnumWorksWithInvalidEnum() {
            Color parsedColor = Color.Blue;

            string fakeColor = "Elijahish";
            bool canParse = fakeColor.TryToEnum<Color>(out parsedColor);
            Assert.AreEqual(false, canParse);
        }

        [TestMethod]
        public void ToEnumWorksWithValidEnum() {
            Color parsedColor = Color.Blue;

            string realColor = "Yellow";
            parsedColor = realColor.ToEnum<Color>();
            Assert.AreEqual(Color.Yellow, parsedColor);
        }

        [TestMethod, ExpectedException(typeof(ArgumentException), "Unable to parse enum")]
        public void ToEnumThrowsExceptionWithInalidEnum() {
            Color parsedColor = Color.Blue;

            string fakeColor = "Elijahish";
            parsedColor = fakeColor.ToEnum<Color>(); 
        }
    }
}

Have you found yourself doing some sort of the same thing? If so, how?

2 comments:

  1. Anonymous9:30 AM

    Yup I pretty much do the same thing. The code I'm working with has a lot of utility functions so I'm slowly working them over into extension methods (ToInt32, TryToInt32, etc.).

    The code samples in your post are showing up as a single line each.

    ReplyDelete
  2. Hi, there is a variation of what you do on my post:

    ReplyDelete