如何在vb.net中实现值类型的C#’as’关键字?

我们的大多数开发都是在vb.net中完成的(不是我的选择),一个常用的代码模式使用’On Error GoTo’后跟’Resume Next’,以便所有数据库字段都可以使用DirectCast()读取DBNull值只是被忽略。

目前的代码是

On Error GoTo error_code oObject.Name = DirectCast(oReader.Item("Name"), String) oObject.Value = DirectCast(oReader.Item("Value"), Integer) error_code: Resume Next 

用C#替换这个代码就可以删除On Error代码了

 oObject.Name = oReader["Name"] as string ?? string.Empty; oObject.Value = oReader["Value"] as int? ?? -1; 

问题是这个C#代码的vb.net eqivelent使用TryCast(),它只能用于引用类型(可空类型是值类型),而C#as关键字可以用于引用和可空类型。

那么总结一下,有没有人有一个vb.net代码的例子,它与每个数据库字段的单行中的C#代码做同样的事情?

-编辑-

在我们的案例中,我已经确定了我认为最好的解决方案。 Helper方法不适合(由于管理),我们不能使用扩展方法,因为我们只使用.NET 2.0(尽管使用VS 2008,因此我们获得了If())

 oObject.Name = If(oReader.IsDBNull(oReader.GetOrdinal("Name")), String.Empty, oReader.GetString(oReader.GetOrdinal("Name"))) oObject.Value = If(oReader.IsDBNull(oReader.GetOrdinal("Value")), 0, oReader.GetInt32(oReader.GetOrdinal("Value"))) 

在VB 9.0中,“IF”是一个真正的合并操作,相当于C#的“??”。 来源MSDN :

所以你可以使用:

 oObject.Name = IF(oReader.Item("Name").Equals(DBNull.Value),string.Empty,DirectCast(oReader.Item("Name"), String)) 

编辑

对不起发芽这样的废话。 我依靠Paul Vick (当时的VB团队负责人)而不是MSDN 发布的post,并没有安装Windows来测试代码。

我仍然会留下我的post – 经过大量修改(参考编辑历史来阅读错误的原始文本) – 因为我发现这些点仍然有一些优点。

那么,再一次,回顾三件事:

  1. 对于引用类型 ,C#是由VB中的TryCast直接建模的。

    但是,C#通过拆箱为值类型的处理增加了一些额外的function(即通过as将值类型拆分为Nullable对应的可能性)。

  2. VB 9提供了If运算符来实现两个不同的C#运算符: null coalescing( ?? )和conditional( ?: :),如下所示:

  ' Null coalescing: ' Dim result = If(value_or_null, default_value) ' Conditional operator: ' Dim result = If(condition, true_value, false_value) 

与之前的IIffunction不同,这些是真正的短路运算符,即只执行必要的部分。 特别是,下面的代码将编译并运行得很好(它不会,使用IIf函数,因为我们可以除以零):

  Dim divisor = Integer.Parse(Console.ReadLine()) Dim result = If(divisor = 0, -1, 1 \ divisor) 
  1. 不要使用VB6样式的error handling( On Error GoTo …On Error Resume [Next] )。 这是易于VB6转换的向后兼容性东西。 相反,使用.NET的exception处理机制,就像在C#中一样。

使用IsDbNull方法检查空值而不是昂贵的try-fail-handlefailure方法。 error handling几乎总是比在条件成为错误之前捕获条件更昂贵。

(另外,error handling应该使用exception,而不是VB6风格的ON ERROR GOTO HELL …)

使用条件If函数看起来像一个单行:

 oObject.Name = If(oReader.IsDbNull(oReader.GetOrdinal("Name")), Nothing, oReader.GetString(oReader.GetOrdinal("Name"))) 

我更愿意编写一些辅助函数,这些函数可用于使代码更具可读性和更高效:

 Function GetStringOrDefault(reader As DbDataReader, key As String) As String Dim ordinal = reader.GetOrdinal(key) If reader.IsDbNull(ordinal) Then Return Nothing Else Return reader.GetString(ordinal) End If End Function 

用法:

 oObject.Name = GetStringOrDefault(oReader, "Name") 

您也可以将它们编写为DbDataReader类的扩展,以使它们更具可读性。

我不认为VB.NET有任何运算符模仿的function?? C#的运营商。 但是,在您的情况下,您可以使用相当于C#的三元运算符 – IIF函数 :

不可否认丑陋:

 oObject.Name = IIf(oReader.Item("Name").Equals(DBNull.Value), DirectCast(oReader.Item("Name"), String), String.Empty) oObject.Value = IIf(oReader.Item("Value").Equals(DBNull.Value), DirectCast(oReader.Item("Value"), Integer), -1) 

请务必阅读我在上面提供的链接中阅读Stephen Weatherford的post,该链接建议使用通用的IIf函数,该函数根据提供的参数推断出类型要求。 这是必要的,因为IIf函数总是返回一个对象!

更好的选择是创建一个有条件地执行此转换的函数,而不是尝试在一行中执行此操作。

每个人都为这次讨论添加了一些有效的观点,所以我想我总结了重点。

  1. VB.net TryCast()与C#作为关键字不同。 如果它是相同的那么首先就不需要这个问题了。

  2. VB.net使用If()函数进行三元运算和空合并运算。 这不像C#版本那样容易阅读(?和??分别)。 尽量避免使用vb.net IIf()函数,因为这不一样。

  3. 空合并代码模式不起作用,因为我们不能将TryCast()与可空类型一起使用,因此我们必须使用三元模式。

  4. oReader.IsDBNull(oReader.GetOrdinal(“Name”))是检查值是否为DBNull的最佳方法。

根据文档,TryCast仅适用于引用类型。 无论如何,使用IDataReader时问题可能比使用trycast更多。

在循环IDataReader中的行之前,获取列名的序数值并使用强类型的GetX方法来检索字段值,如此

 Dim name As Integer = oReader.GetOrdinal("Name") Dim value as Integer = oReader.GetOrdinal("Value") While reader.Read() oObject.Name = if(oReader.IsDbNull(name), string.Empty, oReader.GetString(name)) oObject.Value = if(oReader.IsDbNull(value), -1, oReader.GetInt32(value) End While ' Call Close when done reading. oReader.Close() 

使用带有3个参数的if运算符使其像C#三元布尔运算符eval一样工作?trueExpression:falseExpression

这可以帮助您解决问题。