tags:

views:

181

answers:

3

I'm trying to return a strongly typed Enumeration value from a string. I'm sure there is a better way to do this. This just seems like way too much code for a simple thing like this:

    public static DeviceType DefaultDeviceType
    {
        get
        {
            var deviceTypeString = GetSetting("DefaultDeviceType");
            if (deviceTypeString.Equals(DeviceType.IPhone.ToString()))
                return DeviceType.IPhone;
            if (deviceTypeString.Equals(DeviceType.Android.ToString()))
                return DeviceType.Android;
            if (deviceTypeString.Equals(DeviceType.BlackBerry.ToString()))
                return DeviceType.BlackBerry;
            if (deviceTypeString.Equals(DeviceType.Other.ToString()))
                return DeviceType.Other;
            return DeviceType.IPhone; // If no default is provided, use this default.
        }
    }

Ideas?

Based on the feedback I got from the community, I have decided to use a method extension that converts a string to an enumeration. It takes one parameter (the default enumeration value). That default also provides the type, so the generic can be inferred and doesn't need to be specified explicitly using <>. The method is now shortened to this:

    public static DeviceType DefaultDeviceType
    {
        get
        {
            return GetSetting("DefaultDeviceType").ToEnum(DeviceType.IPhone);
        }
    }

Very cool solution that can be reused in the future.

+15  A: 

Use Enum.Parse():

var deviceTypeString = GetSetting("DefaultDeviceType");
return (DeviceType)Enum.Parse( typeof(DeviceType), deviceTypeString );

If the input is unreliable, you should take care, because you will get a ArgumentException if the value can't be interpreted as one of the values of the enum.

There's also an overload of Parse() that allows you to ignore case when making this conversion, if needed.

LBushkin
@LBushkin Nice, that's way better. Thanks!
Paul Fryer
+13  A: 

If you're dealing with (unreliable) user input, I like to use an extension method that permits a default value. Try it out.

    public static TResult ParseEnum<TResult>(this string value, TResult defaultValue)
    {
        try
        {
            return (TResult)Enum.Parse(typeof(TResult), value, true);
        }
        catch (ArgumentException)
        {
            return defaultValue;
        }
    }
kbrimington
@kbrimington Very Cool, I like the ability to provide a default - I'll probably end up using this. Thanks.
Paul Fryer
This is a good approach. Depending on your version of .NET, the newer Enum.TryParse lets you keep this same method while getting rid of the try block.
TechNeilogy
@TechNeilogy I'm using .net 3.5, didn't see the TryParse method - that must be new with 4.0?
Paul Fryer
Nice! I hadn't known about the new TryParse method. Thanks!
kbrimington
@Paul, I think you're right, I think Enum.TryParse is 4.0. It's really handy that they've added it, too bad it isn't in earlier versions. You could mimic it using an exception-based method for now, then you'll be ready if your project is upgraded.
TechNeilogy
+1  A: 

I wrote this extension method once to convert to any any enum type from string, this way you don't have to write the conversion code over and over again:

    public static class StringExtensions
    {

    public static T ConvertToEnum<T>(this string value)
    {
        //Guard condition to not allow this to be used with any other type than an Enum
        if (typeof(T).BaseType != typeof(Enum))
        {
            throw new InvalidCastException(string.Format("ConvertToEnum does not support converting to type of [{0}]", typeof(T)));
        }


        if (Enum.IsDefined(typeof(T), value) == false)
        {
            //you can throw an exception if the string does not exist in the enum
            throw new InvalidCastException();

            //If you prefer to return the first available enum as the default value then do this
           Enum.GetNames(typeof (T))[0].ConvertToEnum<T>(); //Note: I haven't tested this
        }
        return (T)Enum.Parse(typeof(T), value);
    }
}

To actually use it you can do this:

//This is a enumeration for testing
enum MyEnumType
{
    ENUM1,
    ENUM2
}

//How to cast
var myEnum = "ENUM2".ConvertToEnum<MyEnumType>();

myEnum at this point should equal ENUM2

Roberto Sebestyen
@Roberto That is slick! The only thing I didn't see is how to handle the case when a parse fails, what default should be used? Perhaps I can add an overload to pass the default value into the extension method.
Paul Fryer
I'm thinking if I expose a method that doesn't take a default, then I can just use the first enumeration value (for a default). Do you happen to know how to get the first enumeration value, while using a generic as in the code above?
Paul Fryer
@Paul thanks, well if the parse fails, personally I would want to know about it, and I throw an exception. I would not want to return a default value because that could possibly cause some logic errors, when I am assuming that the parse is working, but it is actually failing and really just returning a default value.
Roberto Sebestyen
@Roberto Good point on the (if parse didn't work, throw).
Paul Fryer
@Paul please see my edits, if you really want to throw a default value anyway, by getting the first enumeration value.
Roberto Sebestyen