Lấy từ sự nhầm lẫn với phân tích cú pháp một Enum
Đây là quyết định của những người đã tạo ra .NET. Một enum được hỗ trợ bởi một kiểu giá trị ( int
, short
, byte
, vv), và vì vậy nó có thể thực sự có giá trị gì đó có giá trị đối với những loại giá trị.
Cá nhân tôi không phải là một fan hâm mộ của cách này hoạt động, vì vậy tôi đã thực hiện một loạt các phương pháp tiện ích:
/// <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);
}
}
Bằng cách này, tôi có thể nói:
if(!sEnum.IsDefined()) throw new Exception(...);
... hoặc là:
EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.
Biên tập
Ngoài giải thích được đưa ra ở trên, bạn phải nhận ra rằng phiên bản .NET của Enum tuân theo mô hình lấy cảm hứng từ C hơn là phiên bản lấy cảm hứng từ Java. Điều này làm cho nó có thể có các enum "Cờ Bit" có thể sử dụng các mẫu nhị phân để xác định xem một "cờ" cụ thể có hoạt động trong một giá trị enum hay không. Nếu bạn phải xác định mọi sự kết hợp có thể có của các cờ (tức là MondayAndTuesday
, MondayAndWednesdayAndThursday
), chúng sẽ vô cùng tẻ nhạt. Vì vậy, có khả năng sử dụng các giá trị enum không xác định có thể thực sự hữu ích. Nó chỉ yêu cầu thêm một chút công việc khi bạn muốn có một hành vi không nhanh trên các loại enum không sử dụng các loại thủ thuật này.