关于vb.net:Ternary运算符VB vs C#:为什么解决Nothing为零?

Ternary operator VB vs C#: why resolves Nothing to zero?

我只是开枪打自己的脚,想知道是否有真正的原因使这种情况成为可能。不管怎样,这个问题可以留到将来的脚枪手方便。

假设我们在vb.net中有一个可以为空的值:

1
Dim i as Integer?

我们希望根据条件和使用三元运算符为其赋值,因为它是如此的简洁和复杂:

1
i = If(condition(), Nothing, 42)

也就是说,如果条件为true,则使用可空性,否则使用值。在哪一点发生了枪击。由于没有明显的原因,vb编译器决定NothingInteger的公共基类型是Integer,此时它会将语句无声地转换为:

1
i = If(condition(), 0, 42)

现在,如果你要用C来做这个:

1
i = (condition()) ? null : 42;

您会立即得到一个编译器错误,说明int不匹配。太好了,如果这次我走C字形,我的脚会更健康。为了进行编译,您必须明确地写下:

1
i = (condition()) ? null : (int?)42;

现在,您可以在vb中执行相同的操作,并获得预期的正确的空值:

1
i = If(condition(), Nothing, CType(42, Integer?))

但这首先需要你的脚被击中。没有编译器错误,也没有警告。那是关于Explicit OnStrict On

所以我的问题是,为什么?我应该把它当作编译器的bug吗?或者有人能解释为什么编译器是这样的吗?


这是因为vb的Nothing不是c的null的直接等价物。

例如,在C中,此代码不会编译:

1
int i = null;

但是这个vb.net代码工作得很好:

1
Dim i As Integer = Nothing

net的Nothing实际上更接近于c的default(T)表达式。


三元运算符只能返回一种类型。

在C中,它试图选择基于null42的类型。那么,null没有类型,所以它决定三元运算符的返回类型是42的返回类型;一个普通的老int返回类型。然后它会抱怨,因为您不能像普通的旧int那样返回空值。当你强制42作为一个int?时,三元运算符将返回一个int?,所以null是有效的。

现在,我不知道vb,但是引用了msdn的话,Assigning Nothing to a variable sets it to the default value for its declared type.

因为vb决定三元运算符返回int(使用同一进程c did),所以Nothing0。同样,强迫42成为int?的做法,会使Nothing变成你所期望的int?的默认值,也就是null的默认值。


我认为这与中情局有更多的关系,而不是什么都没有。考虑此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
''#     This raises an exception
Dim x As Integer?
x = If(True, Nothing, Nothing)
MessageBox.Show(x.Value)

''#     As does
Dim x As Integer?
x = Nothing
MessageBox.Show(x.Value)

''#     Changing one of the truthpart arguments of If is what seems to return the zero.
Dim x As Integer?
x = If(True, Nothing, 5)
MessageBox.Show(x.Value)

为什么要这样做,我仍然不知道,可能是VB团队的一个问题。我不认为这和关键字Nothing或Nullable有关。


Nothingnull不是一回事…来自MSDN:

Assigning Nothing to a variable sets it to the default value for its declared type.

阿尔索

If you supply a value type in Expression, IsNothing always returns False.

别忘了内特?是可以为空的类型,但它仍然是值类型,而不是引用类型。

试着把它设置为DbNull.Value,而不是Nothing


在许多情况下,Nothing将转换为默认值。要使用Nothing,就像使用null一样,需要将其强制转换为正确的可空类型。

1
2
3
4
5
6
7
Dim str As String
Dim int As Nullable(Of Integer) ' or use As Integer?
Dim reader As SqlDataReader
Dim colA As Integer = reader.GetOrdinal("colA")
Dim colB As Integer = reader.GetOrdinal("colB")
str = If(reader.IsDBNull(colA), DirectCast(Nothing, String), reader.GetString(colA))
int = If(reader.IsDBNull(colB), DirectCast(Nothing, Nullable(Of Integer)), reader.GetInt32(colB))

这在VS2015中(至少)是可以通过使用新的整数实现的。

前任。:

If(testInt> 0, testInt, New Integer?), where testInt is of type Integer?


这是因为整数不是引用类型。"Nothing"只适用于引用类型。对于值类型,赋值不会自动转换为默认值,即整数0。