How to achieve the C# 'as' keyword for value types in vb.net?

后端 未结 6 2314
无人及你
无人及你 2020-12-15 10:20

Most of our development is done in vb.net (not my choice) and one frequently used code pattern uses an \'On Error GoTo\' followed by a \'Resume Next\' so that all database f

相关标签:
6条回答
  • 2020-12-15 10:33

    Use the IsDbNull method to check for null values instead of a costly try-fail-handlefailure approach. Error handling is almost always more expensive than catching a condition before it becomes an error.

    (Also, error handling should use exceptions, not VB6-style ON ERROR GOTO HELL...)

    With the conditional If function that would look like this as a one-liner:

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

    I would prefer to write some helper functions that could be used to make the code more readable and more efficient:

    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
    

    Usage:

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

    You could alternatively write them as extensions to the DbDataReader class to make them even more readable.

    0 讨论(0)
  • 2020-12-15 10:40

    In VB 9.0, "IF" is a true coalescing operation equivalent to C#'s "??". Source MSDN:

    So you could use:

    oObject.Name = IF(oReader.Item("Name").Equals(DBNull.Value),string.Empty,DirectCast(oReader.Item("Name"), String))
    
    0 讨论(0)
  • 2020-12-15 10:42

    Everyone has added some valid points to this discussion so I thought I'd summarise the important points.

    1. VB.net TryCast() is NOT the same as the C# as keyword. If it was the same then there would have been no need for this question in the first place.

    2. VB.net uses the If() function for ternary operations and null coalescing operations. This is not as easy to read as the C# version (? and ?? respectivly). Try to avoid the vb.net IIf() function as this is not the same.

    3. The null coalescing code pattern does not work as we cannot use the TryCast() with nullable types so we have to use the terniary pattern.

    4. oReader.IsDBNull(oReader.GetOrdinal("Name")) is the best way to check if a value is DBNull.

    0 讨论(0)
  • 2020-12-15 10:45

    Edit

    Sorry for sprouting such nonsense. I relied on a posting by Paul Vick (then head of the VB team) rather than the MSDN and don't have Windows installed to test the code.

    I'll still leave my posting – heavily modified (refer to the edit history to read the wrong original text) – because I find the points still have some merit.

    So, once again, three things to recap:

    1. For reference types, C#'s as is directly modelled by TryCast in VB.

      However, C# adds a little extra for the handling of value types via unboxing (namely the possibilities to unbox value types to their Nullable counterpart via as).

    2. VB 9 provides the If operator to implement two distinct C# operators: null coalescing (??) and conditional (?:), as follows:

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

    Unlike the previous IIf function these are real short-circuited operators, i.e. only the necessary part will be executed. In particular, the following code will compile and run just fine (it wouldn't, with the IIf function, since we could divide by zero):

        Dim divisor = Integer.Parse(Console.ReadLine())
        Dim result = If(divisor = 0, -1, 1 \ divisor)
    
    1. Don't use VB6 style error handling (On Error GoTo … or On Error Resume [Next]). That's backwards compatibility stuff for easy VB6 conversion. Instead, use .NET's exception handling mechanisms like you would in C#.
    0 讨论(0)
  • 2020-12-15 10:50

    I don't think that VB.NET has any operator that mimics the functioning of the ?? operator of C#. However, you could use the equivalent of C#'s ternary operator - The IIF function in your case:

    Admittedly ugly:

    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)
    

    Please make sure to read Stephen Weatherford's post in the link I provided above which suggests a generic IIf function that infers type requirements from the provided arguments. This becomes necessary because the IIf function always returns an Object!

    A better option would be to create a function that performs this cast conditionally, rather than trying to do it in one line.

    0 讨论(0)
  • 2020-12-15 10:50

    According to the docs TryCast only works with reference types. Regardless, the problem might be more with your usage of the IDataReader than trycast.

    Before looping over the rows in the IDataReader, get the ordinal values of the column names and use the strongly typed GetX methods to retrieve the field values like so

    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()
    

    Using the if operator with 3 parameters like so makes it work like the C# ternary boolean operator eval?trueExpression:falseExpression

    This should help you with your issue.

    0 讨论(0)
提交回复
热议问题