我需要验证一个整数,以确定它是否是有效的枚举值。
在C#中实现这一点的最佳方法是什么?
发布于 2011-01-27 01:02:45
你一定会喜欢这些人,他们认为数据不仅来自用户界面,而且来自你控制的用户界面!
IsDefined适用于大多数场景,您可以从以下开始:
public static bool TryParseEnum<TEnum>(this int enumValue, out TEnum retVal)
{
retVal = default(TEnum);
bool success = Enum.IsDefined(typeof(TEnum), enumValue);
if (success)
{
retVal = (TEnum)Enum.ToObject(typeof(TEnum), enumValue);
}
return success;
}(显然,如果你不认为‘this’是一个合适的int扩展,那就去掉它吧)
发布于 2013-04-02 06:03:57
我的帖子被标记为答案是错误的。
参数和数据验证是我几十年前学到的东西之一。
为什么选择
验证是必需的,因为基本上任何整数值都可以分配给枚举,而不会抛出错误。
我花了很多时间研究C#枚举验证,因为它在许多情况下是一个必要的函数。
所在的
对我来说,枚举验证的主要目的是验证从文件读取的数据:您永远不会知道文件是否已损坏、是否已被外部修改或是否被故意黑客攻击。
使用从剪贴板粘贴的应用程序数据的枚举验证:您永远不会知道用户是否编辑了剪贴板内容。
也就是说,我花了几天的时间研究和测试许多方法,包括分析我能找到或设计的每种方法的性能。
在System.Enum中调用任何东西都是如此之慢,以至于对于包含成百上千个对象的函数来说,这是一个明显的性能损失,这些对象的属性中有一个或多个枚举,必须对边界进行验证。
底线是,在验证枚举值时远离System.Enum类中的所有东西,它非常慢。
结果
我目前用于枚举验证的方法可能会吸引许多程序员的注意,但对于我的特定应用程序设计来说,它是最小的缺点。
我定义了一个或两个常量作为枚举的上界和下界(可选),并在两个if()语句中使用它们进行验证。
一个缺点是,如果更改枚举,则必须确保更新常量。
仅当枚举是"auto“样式时,此方法才有效,其中每个枚举元素都是一个递增的整数值,例如0,1,2,3,4,...它不能与具有非增量值的标志或枚举一起正常工作。
还要注意的是,这种方法几乎和常规int32s上的if "<“">”一样快(在我的测试中,它获得了38,000个滴答)。
例如:
public const MyEnum MYENUM_MINIMUM = MyEnum.One;
public const MyEnum MYENUM_MAXIMUM = MyEnum.Four;
public enum MyEnum
{
One,
Two,
Three,
Four
};
public static MyEnum Validate(MyEnum value)
{
if (value < MYENUM_MINIMUM) { return MYENUM_MINIMUM; }
if (value > MYENUM_MAXIMUM) { return MYENUM_MAXIMUM; }
return value;
}PERFORMANCE
对于那些感兴趣的人,我分析了枚举验证的以下变体,以下是结果。
分析是在release compile上执行的,每个方法都有一个随机整数输入值,循环了一百万次。每个测试都运行了10次以上,并取了平均值。tick结果包括执行的总时间,这将包括随机数生成等,但这些将在测试中保持不变。1刻度=10。
注意,这里的代码不是完整的测试代码,它只是基本的枚举验证方法。还有许多其他的变种进行了测试,所有这些变种的结果都与这里显示的结果相似,这些变种减少了180万个刻度。
列出了从最慢到最快的四舍五入结果,希望没有拼写错误。
在方法中确定的界限= 13,600,000个滴答
public static T Clamp<T>(T value)
{
int minimum = Enum.GetValues(typeof(T)).GetLowerBound(0);
int maximum = Enum.GetValues(typeof(T)).GetUpperBound(0);
if (Convert.ToInt32(value) < minimum) { return (T)Enum.ToObject(typeof(T), minimum); }
if (Convert.ToInt32(value) > maximum) { return (T)Enum.ToObject(typeof(T), maximum); }
return value;
}Enum.IsDefined = 1,800,000刻度
注意:此代码版本不会钳制到最小/最大值,但如果超出范围,则返回默认值。
public static T ValidateItem<T>(T eEnumItem)
{
if (Enum.IsDefined(typeof(T), eEnumItem) == true)
return eEnumItem;
else
return default(T);
}System.Enum转换Int32,投射= 1,800,000刻度
public static Enum Clamp(this Enum value, Enum minimum, Enum maximum)
{
if (Convert.ToInt32(value) < Convert.ToInt32(minimum)) { return minimum; }
if (Convert.ToInt32(value) > Convert.ToInt32(maximum)) { return maximum; }
return value;
}if()最小/最大常数= 43,000滴答=获胜者的速度分别快42倍和316倍。
public static MyEnum Clamp(MyEnum value)
{
if (value < MYENUM_MINIMUM) { return MYENUM_MINIMUM; }
if (value > MYENUM_MAXIMUM) { return MYENUM_MAXIMUM; }
return value;
}-停产-
发布于 2014-12-05 06:16:47
正如其他人提到的,Enum.IsDefined很慢,如果它在循环中,你必须意识到这一点。
进行多个比较时,一种更快的方法是首先将值放入HashSet中。然后只需使用Contains检查该值是否有效,如下所示:
int userInput = 4;
// below, Enum.GetValues converts enum to array. We then convert the array to hashset.
HashSet<int> validVals = new HashSet<int>((int[])Enum.GetValues(typeof(MyEnum)));
// the following could be in a loop, or do multiple comparisons, etc.
if (validVals.Contains(userInput))
{
// is valid
}https://stackoverflow.com/questions/13615
复制相似问题