为什么这两个代码块存储不同的值?

时间:2016-01-11 17:42:23

标签: vb.net entity-framework nullable

设置:

customObject是一个Entity Framework对象,customObject.is_required是一个可以为空的字节字段,表示SQL Server中tinyint的一列,并允许空值。

ddlIsRequired是一个下拉列表,其中包含三个具有以下值的项目:

  • ""(空白)

  • "1"("是")

  • "0"(" no")

请考虑以下代码:

customObj.is_required = If(String.IsNullOrEmpty(ddlIsRequired.SelectedValue), _
                          Nothing, _
                          ddlIsRequired.SelectedValue)

执行时,上面的代码行在可空字节字段customObj.is_required

中存储0
If String.IsNullOrEmpty(ddlIsRequired.SelectedValue) Then
    customObj.is_required = Nothing
Else
    customObj.is_required = ddlIsRequired.SelectedValue
End If

执行时,上面的代码块将Nothing存储在customObj.is_required中,这是我原本期望的内联 - 如果已经完成,但是内联 - if似乎对待{{1} }}字段,好像它不可为空,而是存储任何数字的默认值(零)。

为什么会这样?

2 个答案:

答案 0 :(得分:3)

原因是If函数必须返回给定类型的值。编译器通过查看返回值的两个表达式(第二个和第三个参数)来决定返回什么类型。在您的情况下,一个值为Nothing,另一个值为String。编译器决定可以包含Nothing或String的最简单类型是String。如果选择的值为Nothing,则将其转换为字符串(""),如果您有Option Strict Off(这是一个坏主意),则字符串"& #34;将其分配给字节时转换为0。

如果您想在一个语句中执行此操作,则必须明确返回的表达式为Byte?

customObj.is_required = If(String.IsNullOrEmpty(ddlIsRequired.SelectedValue), Nothing, CType(ddlIsRequired.SelectedValue, Byte?))

答案 1 :(得分:2)

正如Blackwood所述,编译器通过检查最后两个参数的类型自动推断出三元If操作的返回类型。例如:

Dim test As Object = If(True, "1", "2")
Console.WriteLine(test.GetType().Name) ' Outputs "String"
Dim test2 As Object = If(True, 1, 2)
Console.WriteLine(test.GetType().Name) ' Outputs "Int32"

在您的情况下,第一个值是Nothing,因此编译器不能使用它来推断返回类型。然后它查看第二个值并看到它是String(正如您在上面的注释中所述,SelectedValue属性被声明为String属性)。因此,三元操作的返回类型将为String

因此,当它返回Nothing时,它会将其作为String类型返回,然后将其转换为可空字节。换句话说,从长远来看,它是这样做的:

Dim input As String = ddlIsRequired.SelectedValue
Dim stringOutput As String = Nothing
If String.IsNullOrEmpty(input) Then
    stringOutput = Nothing
Else
    stringOutput = input
End If
Dim output As Byte? = CType(output, Byte?)
customObj.is_required = output

而且,因为在VB CType("", Byte?)中返回0,那就是你得到的。您仍然可以使用三元If运算符,只要您将其强制转换为正确的类型:

customObj.is_required = If(String.IsNullOrEmpty(ddlIsRequired.SelectedValue), Nothing, CType(ddlIsRequired.SelectedValue, Byte?))

其中,长篇形式,如下所示:

Dim input As String = ddlIsRequired.SelectedValue
Dim inputNullableByte As Byte? = CType(input, Byte?)
Dim output As Byte? = Nothing
If String.IsNullOrEmpty(input) Then
    output = Nothing
Else
    output = inputNullableByte
End If
customObj.is_required = output

正如其他人所说,通过转动Option Strict On,编译器会强制你以这种方式强制输入类型,否则就不会编译:

Option Strict On
' ...
Dim output As Byte? = If(True, Nothing, "1") ' Compiler error BC30512 Option Strict On disallows implicit conversions from 'String' to 'Byte?'

鉴于:

Option Strict Off
' ...
Dim output As Byte? = If(True, Nothing, "1") ' Works and output gets set to 0