三元运算符 VB 与 C#:为什么将 Nothing 解析为零?

发布于 2024-10-01 14:06:50 字数 1278 浏览 7 评论 0原文

我只是搬起石头砸自己的脚,想知道是否有真正的原因导致这种情况成为可能。
不管怎样,这个问题可以留下来,以方便未来的足射手。


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

Dim i as Integer?

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

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

也就是说,如果条件为 true< /code>,采用可空性,否则采用值。
此时发生枪击事件。没有任何明显的原因,VB 编译器决定 NothingInteger 的公共基类型是 Integer,此时它会默默地将语句翻译为:

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

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

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

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

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

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

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

但这需要首先让你的脚射门。没有编译器错误,也没有警告。这就是Explicit OnStrict On


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

I just shoot myself in the foot and would like to know whether there were actual reasons to make this situation possible.
And anyway, this question can stay for the convenience of the future foot shooters.


Suppose we have a nullable value in vb.net:

Dim i as Integer?

We want to assign a value to it, basing on a condition, and using a ternary operator, because it's so neat and stuff:

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

That is, if a condition is true, employ the nullability, otherwise the value.
At which point the shooting occurs. For no apparent reason VB compiler decides that the common base type for Nothing and Integer is Integer, at which point it silently translates the statement to:

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

Now, if you were to do this in C#:

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

You would immediately get a compiler error saying that <null> doesn't mix well with int. Which is great, as my foot would have been healthier had I went the C# way this time. And for this to compile, you have to explicitly write:

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

Now, you can do the same in VB and get the correct null-ness you would expect:

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

But that requires having your foot shot in the first place. There's no compiler error and there's no warning. That's with Explicit On and Strict On.


So my question is, why?
Should I take this as a compiler bug?
Or can someone explain why the compiler behaves this way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

月亮邮递员 2024-10-08 14:06:50

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

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

int i = null;

但此 VB.Net 代码工作得很好:

Dim i As Integer = Nothing

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

This is because VB's Nothing is not a direct equivalent to C#'s null.

For example, in C# this code will not compile:

int i = null;

But this VB.Net code works just fine:

Dim i As Integer = Nothing

VB.Net's Nothing is actually a closer match for C#'s default(T) expression.

路还长,别太狂 2024-10-08 14:06:50

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

在 C# 中,它尝试根据 null42 选择类型。嗯,null没有类型,所以它决定三元运算符的返回类型是42;一个普通的旧int。然后它会抱怨,因为你不能将 null 作为普通的旧 int 返回。当您将 42 强制转换为 int? 时,三元运算符将返回 int?,因此 null 有效。

现在,我不了解VB,但引用MSDN,
对变量不赋值会将其设置为其声明类型的默认值。

其中,由于 VB 确定三元运算符将返回 int(使用与 C# 相同的过程) ),0。同样,将 42 强制为 int? 会将 Nothing 转换为 int? 的默认值,即null,如您所料。

The ternary operator can only return one type.

In C#, it tries to choose a type based on null and 42. Well, null doesn't have a type, so it decides that the return type of the ternary operator is that of 42; a plain old int. Then it complains because you can't return null as a plain old int. When you coerce 42 as a int?, the ternary operator is going to return an int?, so null's valid.

Now, I don't know about VB, but quoting from the MSDN,
Assigning Nothing to a variable sets it to the default value for its declared type.

Which, since VB determines that the ternary operator will return an int (using the same process C# did), Nothing is 0. Again, coercing the 42 to be an int? turns Nothing into the default value of int?, which is null, as you expected.

与之呼应 2024-10-08 14:06:50

我认为这与 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 无关。

I am thinking this has something more to do with IF than with Nothing. Consider this code:

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

Why it is doing this I still don't know, probably a question for the VB team. I don't think it has to do with the Nothing keyword or Nullable.

夜清冷一曲。 2024-10-08 14:06:50

Nothingnull 不是同一件事......来自 MSDN:

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

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

还记得 int 吗?是可以为 null 的类型,但它仍然是值类型,而不是引用类型。

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

Nothing and null are not the same thing... from the MSDN:

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

Also

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

Keep in mind that int? is a nullable type, but it's still a value type, not a reference type.

Try setting it to DbNull.Value instead of Nothing...

情场扛把子 2024-10-08 14:06:50

在许多情况下,Nothing 会转换为默认值。要以与使用 null 相同的方式使用 Nothing,您需要将其转换为正确的可空类型。

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

In a number of cases Nothing will get converted to the default value. To use Nothing the same way you would use null you need to cast it to the correct nullable type.

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))
败给现实 2024-10-08 14:06:50

发生这种情况是因为 Integer 不是引用类型。 “Nothing”仅适用于引用类型。对于值类型,赋值 Nothing 会自动转换为默认值,即整数 0 的情况。

This happens because Integer is not a reference type. 'Nothing' is only supposed to work for reference types. For value types assigning Nothing is automatically converted to the default value, which is in the case of an Integer 0.

尤怨 2024-10-08 14:06:50

现在实际上可以通过使用 New Integer 在 VS2015 中(至少)实现这一点?

前任。:

If(testInt> 0, testInt, New Integer?),其中 testInt 的类型为 Integer?

This is actually now possible in VS2015 (at the very least) by using New Integer?

Ex.:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文