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

Why do these two blocks of code store different values?

设置:

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

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

考虑以下代码:

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

执行时,上述代码行将0存入可空字节字段customObj.is_required

If String.IsNullOrEmpty(ddlIsRequired.SelectedValue) Then
    customObj.is_required = Nothing
Else
    customObj.is_required = ddlIsRequired.SelectedValue
End If

执行时,上面的代码块将 Nothing 存储在 customObj.is_required 中,这是我期望内联-if 所做的,但内联-if 似乎将 nullable byte 字段就好像它不可为空,而是存储任何数字(零)的默认值。

这是为什么?

原因是 If 函数必须 return 具有给定类型的值。编译器通过查看 return 值(第二个和第三个参数)的两个表达式来决定 return 的类型。在您的例子中,一个值是 Nothing,另一个是字符串。编译器决定可以包含 Nothing 或字符串的最简单类型是字符串。如果选择的值是 Nothing,它将转换为字符串 (""),如果您有 Option Strict Off(这是一个坏主意),则当您将字符串 "" 分配给它时,它会转换为 0一个字节?

如果你想在一个语句中完成,你必须明确 returned 表达式是一个 Byte?

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

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

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,所以编译器不能用它来推断 return 类型。然后它查看第二个值,发现它是 String(正如您在上面的评论中所述,SelectedValue 属性 被声明为 String 属性).因此,三元运算的 return 类型将是 String.

因此,当它 returns Nothing 时,它会将其 return 转换为 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?) returns 0 中,这就是你得到的。你仍然可以使用三元 If 运算符,只要你将它强制为正确的类型:

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

在 long-form 中,看起来像这样:

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