为什么这两段代码存储不同的值?
Why do these two blocks of code store different values?
设置:
customObject
是一个 Entity Framework 对象,customObject.is_required
是一个可为空的字节字段,表示 SQL 服务器中的一个列,该列是 tinyint
并允许空值。
ddlIsRequired
是一个下拉列表,其中包含具有以下值的三个项目:
""
(空白)
"1"
(对于"yes")
"0"
(对于"no")
考虑以下代码:
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
设置:
customObject
是一个 Entity Framework 对象,customObject.is_required
是一个可为空的字节字段,表示 SQL 服务器中的一个列,该列是 tinyint
并允许空值。
ddlIsRequired
是一个下拉列表,其中包含具有以下值的三个项目:
""
(空白)"1"
(对于"yes")"0"
(对于"no")
考虑以下代码:
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