Tomado de Confusion con el análisis de una enumeración
Esta fue una decisión por parte de las personas que crearon .NET. Una enumeración está respaldado por otro tipo de valor ( int, short, byte, etc.), y lo que en realidad puede tener cualquier valor que es válido para los tipos de valor.
Personalmente no soy fanático de la forma en que funciona, así que hice una serie de métodos de utilidad:
/// <summary>
/// Utility methods for enum values. This static type will fail to initialize
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumUtil<T>
where T : struct, IConvertible // Try to get as much of a static check as we can.
{
// The .NET framework doesn't provide a compile-checked
// way to ensure that a type is an enum, so we have to check when the type
// is statically invoked.
static EnumUtil()
{
// Throw Exception on static initialization if the given type isn't an enum.
Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
}
/// <summary>
/// In the .NET Framework, objects can be cast to enum values which are not
/// defined for their type. This method provides a simple fail-fast check
/// that the enum value is defined, and creates a cast at the same time.
/// Cast the given value as the given enum type.
/// Throw an exception if the value is not defined for the given enum type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="enumValue"></param>
/// <exception cref="InvalidCastException">
/// If the given value is not a defined value of the enum type.
/// </exception>
/// <returns></returns>
public static T DefinedCast(object enumValue)
{
if (!System.Enum.IsDefined(typeof(T), enumValue))
throw new InvalidCastException(enumValue + " is not a defined value for enum type " +
typeof (T).FullName);
return (T) enumValue;
}
/// <summary>
///
/// </summary>
/// <param name="enumValue"></param>
/// <returns></returns>
public static T Parse(string enumValue)
{
var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
//Require that the parsed value is defined
Require.That(parsedValue.IsDefined(),
() => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}",
enumValue, typeof(T).FullName)));
return parsedValue;
}
public static bool IsDefined(T enumValue)
{
return System.Enum.IsDefined(typeof (T), enumValue);
}
}
public static class EnumExtensions
{
public static bool IsDefined<T>(this T enumValue)
where T : struct, IConvertible
{
return EnumUtil<T>.IsDefined(enumValue);
}
}
De esta manera, puedo decir:
if(!sEnum.IsDefined()) throw new Exception(...);
... o:
EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.
Editar
Más allá de la explicación dada anteriormente, debe darse cuenta de que la versión .NET de Enum sigue un patrón más inspirado en C que uno inspirado en Java. Esto hace posible tener enumeraciones de "Indicador de bit" que pueden usar patrones binarios para determinar si un "indicador" particular está activo en un valor de enumeración. Si tuviera que definir todas las combinaciones posibles de banderas (es decir MondayAndTuesday, MondayAndWednesdayAndThursday), estas serían extremadamente tediosas. Por lo tanto, tener la capacidad de usar valores de enumeración indefinidos puede ser realmente útil. Solo requiere un poco de trabajo extra cuando desea un comportamiento a prueba de fallas en los tipos de enumeración que no aprovechan este tipo de trucos.