65.9K
CodeProject 正在变化。 阅读更多。
Home

从不可靠的数据源设置枚举器 (针对 C# 和 VB)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2010年2月20日

CPOL

2分钟阅读

viewsIcon

18149

避免在从未知/不受信任的来源设置枚举器时发生异常。

引言

这篇文章最初发表在 Wicked Code 论坛,但那是在 Tips/Tricks 流行起来之前,所以我把它搬到了这里。我开始编程几乎 30 年前。在这段时间里,我对用户及其恶作剧,以及其他程序员对确保数据有效性漠不关心的态度,都产生了深深的不信任感。

我们为什么在这里 (给 C# 开发者)

我在 .Net 中遇到的一个问题是在数据源中存储和检索枚举器值,以及准备代码以优雅地处理手动转换值 - 这些值可能被用户修改、被程序员错误设置或解释,或者在没有适当通知相关程序员的情况下被重构。为了节省大量时间,我创建了一些方法,并将它们包含在几乎我编写的每个程序中。
public static T IntToEnum<T>(int value, T defaultValue)
{
    T enumValue = (Enum.IsDefined(typeof(T), value)) ? (T)(object)value 
                                                     : defaultValue;
    return enumValue;
}
该方法的目的是允许程序员将指定枚举器类型的成员变量初始化为序数列表中包含的值。此方法解决的问题是,如果程序员将 enum 序数值作为 int 类型检索,并希望初始化 enum 数据成员,他实际上无法通过编程方式确定该值是否代表有效的序数。他只是尝试设置它,并希望一切顺利(如果赋值出错则处理异常)。此方法允许程序员进行相同的尝试,但结果可控,从而避免了使用无效序数值时必然产生的异常。用法如下所示
enum SomeEnum { Zero=0, Five=5, Six=6, Eight=8 };

// this will result in the correct expected value - SomeEnum.Five
SomeEnum value = IntToEnum(5, SomeEnum.Zero);

// this will result in SomeEnum.Zero because the value (4) isn't a 
// valid ordinal in the enumerator
value = IntToEnum(4, SomeEnum.Zero);
很好,对吧?但是如果 enum 值存储为 string 呢?我有一个答案,它看起来很像第一个。
public static T StringToEnum<T>(string value, T defaultValue)
{
    T enumValue = (Enum.IsDefined(typeof(T), value)) ? 
                   (T)Enum.Parse(typeof(T), value) : 
                   defaultValue;
    return enumValue;
}
给定第一个用法示例中定义的 enum,您将执行如下操作
// this will result in the correct expected value - SomeEnum.Five
SomeEnum value = StringToEnum("5", SomeEnum.Zero);

// this will result in SomeEnum.Zero because the value (4) isn't a 
// valid ordinal in the enumerator
value = StringToEnum("4", SomeEnum.Zero);

给 VB.Net 开发者

最近,我做了一份工作,迫使我用 VB.Net 编码。对于所有 VB.Net 开发者来说,这是将相同的代码转换为您首选/被迫使用的语言。
Public Shared Function IntToEnum(Of T)(value As Integer, defaultValue As T) As T
    Dim enumValue As T = If(([Enum].IsDefined(GetType(T), value)), _
                             DirectCast(DirectCast(value, Object), T), _
                             defaultValue)
    Return enumValue
End Function

Public Shared Function StringToEnum(Of T)(value As String, defaultValue As T) As T
    Dim enumValue As T = If(([Enum].IsDefined(GetType(T), value)), _
                            DirectCast([Enum].Parse(GetType(T), value), T), _
                            defaultValue)
    Return enumValue
End Function

结束语

对于给定的问题,有许多不同的实现方式可以编码。有些人可能更喜欢 TryParse/处理错误 方法来实现此代码,这很好。这就是编码如此有趣的地方。您可以从截然不同的角度解决相同的问题,并且仍然是正确的。

编辑

2011 年 7 月 9 日 = 修复了代码片段中的尖括号显示问题,以及一些拼写错误。2010 年 5 月 5 日 - 字符串版本在 Silverlight 3 中有所不同。您需要向 Parse 方法调用添加第三个参数,以指示您是否希望区分大小写。
© . All rights reserved.