三元运算符VB vs C#:为什么解决Nothing为零?

时间:2010-11-10 17:35:21

标签: c# vb.net nullable ternary-operator

我只是在脚下射击,想知道是否有实际的理由使这种情况成为可能 无论如何,这个问题可以留给未来的脚射手。


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

Dim i as Integer?

我们希望根据条件为其分配一个值,并使用三元运算符,因为它非常简洁:

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

也就是说,如果条件是true,则使用可空性,否则使用值 射击发生的时间点。由于没有明显的原因,VB编译器决定NothingInteger的公共基类型是Integer,此时它会将语句静默转换为:

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

现在,如果您要在C#中执行此操作:

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

您会立即收到编译错误,指出<null>int不能很好地混合。这很棒,因为这次我采用C#方式,我的脚会更健康。为了编译,你必须明确地写:

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

现在,你可以在VB中做同样的事情并获得你期望的正确空值:

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

但这需要首先拍摄你的脚。没有编译器错误,也没有警告。那是Explicit OnStrict On


所以我的问题是,为什么? 我应该将此作为编译器错误吗? 或者有人可以解释为什么编译器会这样做?

7 个答案:

答案 0 :(得分:34)

这是因为VB的Nothing并不等同于C#的null

例如,在C#中,此代码将无法编译:

int i = null;

但是这个VB.Net代码运行得很好:

Dim i As Integer = Nothing

VB.Net的Nothing实际上更接近于C#的default(T)表达式。

答案 1 :(得分:12)

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

在C#中,它会尝试根据null42选择一种类型。好吧,null没有类型,所以它决定三元运算符的返回类型是42的返回类型;一个普通的int。然后它会抱怨因为你不能将null作为普通的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#进程),Nothing0。同样,强制42成为int?Nothing变为默认值int?,即null,如您所料。

答案 2 :(得分:2)

来自MSDN:

Nothingnull并不是一回事......

  

为变量赋值Nothing将其设置为其声明类型的默认值。

另外

  

如果在Expression中提供值类型,则IsNothing始终返回False。

请记住int?是一个可以为空的类型,但它仍然是值类型,而不是引用类型。

尝试将其设置为DbNull.Value而不是Nothing ...

答案 3 :(得分:2)

我认为这与IF有关,而与Nothing有关。请考虑以下代码:

''#     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有关。

答案 4 :(得分:1)

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

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

答案 5 :(得分:-1)

这是因为Integer不是引用类型。 'Nothing'仅适用于参考类型。对于值类型,分配Nothing会自动转换为默认值,如果是整数0,则为

答案 6 :(得分:-1)

这实际上现在可以在VS2015(至少)使用New Integer?

例如:

  

if(testInt&gt; 0,testInt,New Integer?),其中testInt的类型为Integer?