Dec 092009
 

I’ve finally gotten around to finishing this second post. The first part of the Post can be viewed here.

In my first fun with enumerations post I went over how to use an enumeration as a data source. That is all good and dandy when you are working with enumerations and want to put them into the data base. But what happens when you need to pull that value out of the database and convert it back into an enumeration. This is a problem that I have been faced with in the past.

Previously my method was to convert the value out of the database to an integer and then use a switch statement to compare it to all the integer values of the enumerations. This worked, but there are several flaws with this method. First off the major flaw is if a value is added to the enumeration collection then you would have to go through every location where it was pulled out of the database and update the corresponding switch statements to account for the added option. This could possibly be very time consuming if the enumeration is used in numerous locations. Another problem is switch statements are inefficient in execution for various reasons that is an entirely different topic.

This is what lead me to the the methods below. These methods are designed to work as a catch all for any type of enumeration, they take in the values as either an integer or character. The reason for the availability of a character object type being passed in is because characters can be used in enumerations because they are able to be directly converted to an integer and characters are easier to read in database fields. Again though I digress away from the purpose of this entry so lets walk through.

There are two methods in my example below, the first of which contains the core functionality which i’m going to discuss. The second method is an overloaded example that I will go into more detail about as it contains a different idea for how to handle the value not being found. First off we have three parameters that go into the first method. They is the Type Param T and then two object values Value and DefaultValue. These two values are exactly what they sound like, the first is the value you want to find in the enumeration and the second is the default value you want to use if it is not found. The type param is the enumeration type that you want to use, this is also the type that is returned by the method.

Inside the method we declare two variables an int and a char. In most cases the integer is all we’ll need, but the character is there in case the value you are looking for comes in as a single character string. As discussed previously char values can be set for the values of enumeration members so we need logic that will convert the single character string to a char value and then to an int. These values are used in the next if else if block of code. We have two different TryParse method calls here, the first tries to parse the value to an integer and if that fails it then tries to parse the value to a char. Inside both of these if statements the code is very similar, the only difference being the variables that are used, first we check to see if the value is defined within the enumeration type if it is then we create the enumeration object and return it. If it is not defined or if either of the parsings fail we go onto the next section of code dealing with the default value.

There are two different ways this method expects the default value, either as an enumeration object of the type specified or as a value that is defined within the enumeration. The first statement within this block checks to see if the value type that is passed in is the same as the type param. If it is we simple cast the default value from an object back to the enumeration type and return it. The second and third statements within this if block are almost the exact same as the first part of this method, but instead of using the value they use the default value parameter. We try and parse the value as either an integer or char, check if it’s defined and if so return it.

If the method reaches the end and still has not returned a value it returns the default value of the enumeration type param. The default value of an enumeration is either the first enumeration that appears in a list that does not have values specified or is the enumeration that has a value of zero. It should be noted that in an enumeration list where values are specified the first item in the list has a value of zero, thus no matter what you get the enumeration with a value of zero. If no enumeration has a value of zero then you simply get the value of zero as your enumeration when returns without a hitch, just won’t be able to be defined with code.

The second method is a different version of the first method. The logic is similar, but instead of taking in a default value if the value of the enumeration is not specified it throws an exception to be caught by the code that is calling the method. This method is handy in case you want to stop functionality of the calling method if the enumeration you are looking for is not defined.

I’m currently working all this logic into a test project which I hope to have posted on code project before the end of the year for all to see. Just remember enumerations are fun and exciting, if you know how to use them correctly.

/// <summary>
/// Converts an object into its corresponding enumeration member of the provided enumeration type.
/// Uses a default vaule if the value specified does not exist within the Enumeration Type
/// </summary>
/// <typeparam name="T">The Enumeration Type to convert the value to</typeparam>
/// <param name="Value">The value to be converted</param>
/// <param name="DefaultValue">The Default Value to be used</param>
/// <returns>The enumeration member</returns>
public static T ToEnumFromValue<T>(object Value, object DefaultValue)
{
    char cValue;
    int iValue;
    if (Value != null)
    {
        if (int.TryParse(Value.ToString(), out iValue))
        {
            if (Enum.IsDefined(typeof(T), iValue))
            {
                return (T)Enum.ToObject(typeof(T), iValue);
            }
        }
        else if (char.TryParse(Value.ToString(), out cValue))
        {
            if (Enum.IsDefined(typeof(T), (int)cValue))
            {
                return (T)Enum.ToObject(typeof(T), (int)cValue);
            }
        }
    }
    if (DefaultValue != null)
    {
        if (DefaultValue.GetType() == typeof(T))
        {
            return (T)DefaultValue;
        }
        else if (int.TryParse(DefaultValue.ToString(), out iValue))
        {
            if (Enum.IsDefined(typeof(T), iValue))
            {
                return (T)Enum.ToObject(typeof(T), iValue);
            }
        }
        else if (char.TryParse(DefaultValue.ToString(), out cValue))
        {
            if (Enum.IsDefined(typeof(T), (int)cValue))
            {
                return (T)Enum.ToObject(typeof(T), (int)cValue);
            }
        }
    }

    return default(T);
}

/// <summary>
/// Converts an object into its corresponding enumeration member of the provided enumeration type.
/// </summary>
/// <typeparam name="T">The Enumeration Type to convert the value to</typeparam>
/// <param name="Value">The value to be converted</param>
/// <returns>The enumeration member or throws an exception if non-existant</returns>
public static T ToEnumFromValue<T>(object Value)
{
    char cValue;
    int iValue;
    if (Value != null)
    {
        if (int.TryParse(Value.ToString(), out iValue))
        {
            if (Enum.IsDefined(typeof(T), iValue))
            {
                return (T)Enum.ToObject(typeof(T), iValue);
            }
        }
        else if (char.TryParse(Value.ToString(), out cValue))
        {
            if (Enum.IsDefined(typeof(T), (int)cValue))
            {
                return (T)Enum.ToObject(typeof(T), (int)cValue);
            }
        }
    }

    throw new Exception("Value (" + Value.ToString() + ") does not exist in enumeration type (" + typeof(T).ToString() + ")");
}

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>