Pris de Confusion avec l'analyse d'un Enum
C'était une décision de la part de ceux qui les ont créés .NET. Un enum est soutenu par un autre type de valeur (int
, short
, byte
, etc), et donc cela peut avoir n'importe quelle valeur qui est valable pour les types de valeur.
Personnellement, je ne suis pas un fan de la façon dont cela fonctionne, j'ai donc fait une série de méthodes de service:
/// <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);
}
}
De cette façon, je peux dire:
if(!sEnum.IsDefined()) throw new Exception(...);
... ou:
EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.
Modifier
Au-delà de l'explication donnée ci-dessus, vous vous rendez compte que l' .La version NET de Enum suit un plus C-modèle inspiré de Java est inspiré. Cela permet d'avoir de "Petit Pavillon" les énumérations qui peut utiliser des schémas binaires, afin de déterminer si un "drapeau" est active à une valeur d'enum. Si vous deviez définir toutes les combinaisons possibles de drapeaux (c - MondayAndTuesday
, MondayAndWednesdayAndThursday
), celle-ci serait extrêmement fastidieux. Donc, avoir la capacité de utiliser pas défini les valeurs de l'enum peut être vraiment pratique. Il faut juste un peu de travail supplémentaire si vous voulez un fail-fast comportement sur les types enum que de ne pas tirer parti de ces sortes de trucs.