在VB.NET中如下代码:
Dim myBool As Boolean = False
Dim myDate As Date? = If(myBool, Date.Today, Nothing)
Console.WriteLine(myDate)
生产:
1/1/0001 12:00:00 AM
但是,如果我将其写为:
Dim myBool As Boolean = False
Dim myDate As Date?
If myBool Then
myDate = Date.Today
Else
myDate = Nothing
End If
Console.WriteLine(myDate)
然后它会如预期的那样打印 null/nothing。
这是怎么回事,我怎样才能用一个单行代码将日期或 null 分配给 VB.NET 中的可空 DateTime,而不使其实际上默认为01/01/0001 12:00:00 AM
?
该
If(myBool, Date.Today, Nothing)
表达式必须独立存在,并且在不受赋值左侧任何影响的情况下进行计算;它不知道它将被分配给 Nullable DateTime。这对于 VB.Net 来说是不幸的,但在考虑 Nullable 类型时,我们必须记住,这些类型是在首先考虑 C# 的 概念的情况下构建的
null
,这与VB.Net 中的不同Nothing
,因此考虑代码的 C# 适应通常很有用。具体来说,Nothing
实际上更接近 C# 的default(T)
表达式(或者现在只是default
),对于DateTime
值来说是DateTime.MinValue
。这意味着原始代码行的实际直接 C# 翻译如下所示,其中
null
从未使用过:您会发现这与您已经观察到的 VB.Net 行为相匹配。因此,我们看到表达式的最终结果是一个标准(不可为空)
DateTime
值,其中Nothing
被解释为该类型的默认值...这看起来就像1/1/0001 12:00:00 AM
写入系统上的控制台时一样。值得注意的是,
Nothing
表达式在代码的 If/Else 版本中也必须独立存在,同样不考虑赋值的左侧。这次它按预期工作,因为现在C# 翻译
default
中的被视为引用而不是值,因此结果是 true,而不是值类型的非 null 默认值。null
而且,这个
Else
块不是必需的,如果完全省略,您将得到相同的结果。要创建所需的结果,您可以这样做:
或这个:
或者,我可以使用额外的一行:
完全理解这一切的最后一个难题是
If()
forIf(myBool, Date.Today, Nothing)
条件表达式不是函数调用。它确实有一些函数语义,但If()
这里实际上是一个运算符。这允许编译器对其进行特殊处理,因此
Nothing
可以对用作第二个参数的值进行评估以考虑表达式的类型Date.Today
。否则,每个函数参数在进入函数之前都必须完全独立解析,并且Nothing
仍将是非类型化(或Object
)null
引用。我相信这个问题是由于 VB 关键字Nothing的双重性质以及它在将 null 值分配给可空类型时可能引起的混乱造成的。
Date?
是 的简写Nullable(of DateTime)
。当你写:
如果您认为
Nothing
意味着 null,则编译器必须If(...)
根据提供的参数确定关键字返回的类型。Date.Today
显然是一种DateTime
类型,并且Nothing
可以被解释为类型的默认值DateTime
,因此它选择DateTime
作为返回类型,因为它可以隐式转换为Nullable(of DateTime)
。如果您尝试将 C# 等效内容编写为:
C# 编译器会将其标记为错误“无法确定条件表达式的类型,因为‘DateTime’和‘DateTime’之间没有隐式转换
<null>
”。考虑到这一点,人们可以说这是 VB 编译器中的一个“错误”,应该解决。正如其他答案指出的那样,解决方案是让代码明确说明子句返回的内容
If(...)
并替换Nothing
为 Nullable(Of DateTime)` 值,例如:我相信这会起作用。