【问题标题】:Ternary operator VB vs C#: why resolves Nothing to zero?三元运算符 VB 与 C#:为什么将 Nothing 解析为零?
【发布时间】:2011-05-08 00:45:21
【问题描述】:

我只是朝自己的脚开枪,想知道是否有真正的理由使这种情况成为可能。
而且无论如何,为了方便未来的射手,这个问题可以保留。


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

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


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

【问题讨论】:

  • 因为,正如您所发现的那样,VB 是一种可怕的语言,它会做一些您没有要求它做的随机事情,以提供帮助。
  • @cdhowie - 除非你已经尝试了几个星期,否则不要敲它。 VB.Net 与 vb6 相比已经走了很长一段路。
  • @Joel:我同意这一点,但抛光的粪便仍然是粪便。 :)
  • @cdhowie 任何没有学习过新语言特殊功能的人都会觉得这种语言令人沮丧。任何将这种挫败感归咎于语言的人都需要重新考虑他们的反应。
  • @Alex Nah,我是使用过很多种不同语言的人之一。我开始使用 C64 BASIC 进行编程,然后从那里转到 VB1,最后转到 VB4、5、6 和 .NET。这并不是说我没有接触过 VB 块,这使它成为我的语言和其他人一样多。我已经忍受了足够长的时间来知道我为什么不喜欢它。

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


【解决方案1】:

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

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

int i = null;

但是这个 VB.Net 代码工作得很好:

Dim i As Integer = Nothing

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

【讨论】:

  • 是的,这是一个错字。现在修好了。
  • 呸,有那么几秒钟我以为我将不得不修复很多代码!
  • 这解释了为什么int i = null; 不起作用,但如果int? i = 0;int? i = null 都起作用,为什么int? i = condition()? null : 0; 不起作用???
  • @Jon 我无法回答,但他在询问 vb 代码。 vb 到 c# 的翻译更像是int? i = condition()?default(int):0;
  • @JonB 实际上,我现在可以回答这个问题了。 condition()?null:0 表达式必须独立存在;任务的目标无关紧要。当编译器推断表达式的类型时,无类型的null0 操作数显然不兼容,因为int? 仍然是值类型,还有其他“魔法”允许您分配@987654336 @给它。如果编译器足够聪明,可以在这种情况下选择int?,那就太好了,但它还不会这样做。
【解决方案2】:

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

在 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,正如您所期望的那样。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 这与 Nothing 是关键字而不是值有关。正如公认的答案所指出的那样,没有什么真正意味着默认(T)。那么,在您的第一个示例中,T 评估为整数?在你的第二个它评估为整数。哪个符合您的结果。
    【解决方案4】:

    Nothingnull 不是一回事...来自 MSDN:

    将 Nothing 分配给变量会将其设置为其声明类型的默认值。

    还有

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

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

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

    【讨论】:

      【解决方案5】:

      在许多情况下,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))
      

      【讨论】:

        【解决方案6】:

        这是因为 Integer 不是引用类型。 'Nothing' 仅适用于引用类型。对于值类型,赋值 Nothing 会自动转换为默认值,即 Integer 0。

        【讨论】:

          【解决方案7】:

          这实际上现在在 VS2015 中(至少)通过使用 New Integer 是可能的?

          例如:

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

          【讨论】:

          • testIntInteger? 类型的事实已经使整个表达式Integer?,不需要New Integer?。早在 VS2015 之前,这就是可能的,这不是问题所在。
          猜你喜欢
          • 2014-05-04
          • 1970-01-01
          • 2012-03-09
          • 2014-12-09
          • 2021-04-28
          • 2014-09-02
          • 2015-09-26
          • 2013-07-30
          相关资源
          最近更新 更多