我正在将字符串类型的数值转换为相应的枚举。当我测试我的代码时,我发现有趣的行为令我感到困惑。
使用下面的代码示例,如果/当“s”变量的值与其中一个Enum值不匹配时,有人可以阐明为什么不抛出异常?另外,如何将sEnum var设置为Stooge枚举定义中不存在的值?
class Program
{
enum Stooge
{
Unspecified,
Moe,
Larry,
Curly,
Shemp
}
static void Main(string[] args)
{
while (true)
{
Console.WriteLine("Enter a number...");
string s = Console.ReadLine();
Stooge sEnum = (Stooge)(int.Parse(s)); //Why doesn't this line throw if s != 0, 1, 2, 3, or 4?
Console.WriteLine("\r\nYou entered: {0}\r\nEnum String Value: {1}\r\nEnum Int Value: {2}\r\n", s, sEnum.ToString(), (int)sEnum);
}
}
}
答案 0 :(得分:9)
这是创建.NET的人的决定。枚举由另一个值类型(int
,short
,byte
等)支持,因此它实际上可以具有对这些值类型有效的任何值。
我个人并不喜欢它的工作方式,所以我制作了一系列实用方法:
/// <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);
}
}
这样,我可以说:
if(!sEnum.IsDefined()) throw new Exception(...);
......或:
EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.
答案 1 :(得分:2)
enum在技术上只是一个int(或者你已经定义了enum的底层类型)。您可以通过调用Enum.IsDefined
来检查枚举中的相应值。更多信息:Cast int to enum in C#
答案 2 :(得分:1)
Enum是int
的超薄包装器。基本上它是int
+可能值的静态集合(一类常量)。所有的检查都是在编译时,类型检查等。但是当你实际将int
转换为enum
运行时并不关心。所以验证你的输入!
答案 3 :(得分:0)
我将实现从https://stackoverflow.com/a/4892571/275388更改为解决两个问题
DefinedCast(object enumValue)
签名表明该代码可以与string
和int
类型一起使用(并且在以后也不需要装箱)。Enum.IsDefined
/ Enum.Parse
都通过Enum.GetValues(typeof(TEnum))
分配了一个数组,这实际上导致了我的用例的速度变慢-可以避免这样做,但要以缓存地图为代价。因此我很想念
public static class EnumExtensions
{
public static TEnum DefinedCast<TEnum>(string value)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!MapByString<TEnum>.Instance.TryGetValue(value, out TEnum @enum))
{
throw new InvalidCastException(FormattableString.Invariant($"'{value}' is not a defined value"));
}
return @enum;
}
public static TEnum DefinedCast<TEnum>(int value)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!MapByInteger<TEnum>.Instance.TryGetValue(value, out TEnum @enum))
{
throw new InvalidCastException(FormattableString.Invariant($"'{value}' is not a defined value"));
}
return @enum;
}
private static class MapByInteger<TEnum>
where TEnum : struct, IComparable, IFormattable, IConvertible
{
public static readonly Dictionary<int, TEnum> Instance = ((TEnum[])Enum.GetValues(typeof(TEnum))).ToDictionary(e => (int)Convert.ChangeType(e, typeof(int), CultureInfo.InvariantCulture));
}
private static class MapByString<TEnum>
where TEnum : struct, IComparable, IFormattable, IConvertible
{
public static readonly Dictionary<string, TEnum> Instance = ((TEnum[])Enum.GetValues(typeof(TEnum))).ToDictionary(e => e.ToString(CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase);
}
}
答案 4 :(得分:-1)
如果在传递的值不可解析的情况下抛出异常,请使用int.Parse()。如果要解析可能无效的值而不抛出异常,请使用int.TryParse()。