C#中的Null与VB.NET中的Nothing的区别

18

C#中的NULL和vb.net中的Nothing有什么不同?

Console.WriteLine(Nothing = "") => True

对比

Console.WriteLine(null==""); => False

我的理解是,nullNothing 是相同的。但上面的代码清楚地说明它们并不相同。

C# 中的 null 在 VB.NET 中等价于什么?


4
我不确定这个问题怎么会主要基于个人观点,Nothingnull的含义已经被非常明确地定义了。 - jrh
如果Nothing更像default,那么我希望在VB.Net中Nothing = ""为false,因为string是引用类型,除非它不是。 - juharr
@jrh - 在这两者的组合中,它完全取决于它是引用、值还是可空值。所有CLR语言中的类型都保持不变;并且所有CLR类型(String、Int32)在C#(作为string、int的别名)和VB(String、Integer)中只是别名。 - Mad Myche
1
Reddy,你是在寻找VB.NET中与C#的null完全等效的内容,还是只是寻找类似于null的东西(即Nothing)?请更新您的帖子以澄清,这样这里就只有一个问题了。 - jrh
@jrh,我正在尝试找到C#中null的差异和VB.Net中的等效项。我可能会在一个帖子中问两个问题而违反社区规则。但是,我只是想清楚地了解情况。 - BetterLateThanNever
显示剩余3条评论
4个回答

13
您选择了一个有点复杂的例子来测试 vb.net 中的 Nothing 和 C# 中的 null 之间的区别。
从 Visual Basic 语言规范关于 Nothing 的说明:

Nothing 是一个特殊的字面量;它没有类型,并且可以转换为类型系统中的所有类型,包括类型参数。当转换为特定类型时,它等价于该类型的默认值。

如果您阅读 Microsoft 文档中关于 默认值表达式 的描述,您会注意到 vb.net 中的 Nothing 和 C# 中的 default(T) 具有类似的行为。
例如:
Dim isSomething As Boolean = Nothing ' = False
Dim amount As Integer = Nothing ' = 0
Dim value As String = Nothing ' = null (notice not empty string!)

作为证明,字符串的默认值不是空字符串,正如这里的许多评论/答案所说。
Dim value As String = Nothing
If value.Equals("") Then ' will throw NullReferenceException

End If 

比较Nothing和空字符串""使用"="运算符在vb.net中是特殊情况,因为对于字符串来说Nothing将会被解析为null
关于类型String的关系运算符,来自Visual Basic语言规范的说明:
操作符返回通过二进制比较或文本比较两个值的结果。使用的比较由编译环境和Option Compare语句确定。二进制比较确定每个字符串中每个字符的数字Unicode值是否相同。文本比较根据.Net Framework上正在使用的当前区域设置进行基于Unicode文本的比较。在进行字符串比较时,null引用等同于字符串文字""。 在vb.net中检查字符串相等性应该使用String.Equals方法或Is运算符。
基于以上语言规范,
我认为null和Nothing是相同的,但以上代码清楚地解释了它们的不同之处。

这两者并不相同,Vb.net 中的 Nothing 相当于 C# 中的 default(T)

C# 中的 null 在 VB.NET 中有什么等价物?

在 C# 中,您无法将 null 设置为值类型,因此对于引用类型(String),在 vb.net 中与 C# 中的 null 等效的是 Nothing
例如:(null == default(String))


2
这是明确说明VB的“Nothing”和C#的“null” 是不同概念的答案。只有应用于引用类型时,这些概念才是相同的。 - Dave Doknjas
“代表”和“是”是完全不同的东西。继续阅读下面的段落和注释,以了解它的含义。“代表”意味着它被用作语法快捷方式,将默认值分配给任何数据类型,正如您的示例所示,但它不是默认值本身,永远不可能是。你怎么能在非空的Integer中存储Nothing?实际上,如果您删除= Nothing,您的示例仍将工作并产生相同的结果,因为VB自动初始化变量,而C#则不然。 - Racil Hilan
@RacilHilan,不错的“吹毛求疵”评论 ;) - Fabio
@Nyerguds 是的,那是显而易见的。就像我所说的“任何好的开发人员都应该知道的原因”。我所说的异常情况是指数据类型中的例外情况,因为 String 被 MSDN 视为数据类型,尽管它实际上是一个引用类型,正如你所提到的。然而,这并不像你所说的“与普遍信仰相反”,每个好的程序员都必须知道这一点。这就是为什么我没有费心解释它,但还是感谢你的澄清 :) - Racil Hilan
太多了,无法放在评论中。我把它们作为答案发布了。如果感兴趣,您可以看一下。最重要的是:Nothing并不总是等同于default(T),在某些情况下它实际上等同于null。它是一个具有双重用途的关键字,就像=运算符一样。这很令人困惑,语法也很差,但我们必须接受它。 - Racil Hilan
显示剩余11条评论

11

在你的代码中,VB猜测你正在比较字符串,因为其中一个操作数是String类型。在String比较中,Nothing等同于空的String ""。然后它进行值比较,返回True

使用Is来比较引用:

Console.WriteLine(Nothing Is "") '=> False

1
虽然您的答案是正确的,但我不认为前两个句子是正确的。我认为“=”运算符除了进行转换之外什么都不做。如果两个操作数类型不同,VB会将一个操作数转换为匹配另一个操作数的类型。C#在某些情况下也会这样做,但在这种情况下(Nothing =“”)不会这样做,但是例如如果一个操作数是“Single”,而另一个操作数是“Double”。我更新了您的答案,以删除前两个不正确的行。如果您不同意,请回滚。 - Racil Hilan
1
@RacilHilan 是的,你是正确的。我使用ILDASM检查过了,VB的=运算符与C#的==运算符(op_Equality)是相同的。 - SSS
1
其实,我有点说得过早了。还有一个 IL 函数 Microsoft.VisualBasic.CompilerServices.Operators::CompareObjectEqual。(参见https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.compilerservices.operators.compareobjectequal(v=vs.110).aspx)。但是我认为它已经足够复杂,你所做的修改是很好的。 - SSS
这个语句是不正确的。String 类型的默认值是 null,而非空字符串 "" - Fabio
@Fabio 现在这就是“吹毛求疵”了 :). 当然你是对的,因为String实际上是一个引用。感谢您的评论,我会相应地更新答案。我希望SSS能接受这个。 - Racil Hilan

1
接受答案的最终版本正确回答了问题。然而,Fabio在他的答案中添加了一些有用的信息,但其中有一些错误的信息和概念。因此,这个答案试图将两个答案合并成一个更完整的、正确的答案。
首先,VB中的Nothing相当于C#中的null,所以你的理解是正确的,至少部分正确(因为这只是Nothing关键字的一个用法)。虽然这已经反映在MSDN文献中,但最近已经逐渐消失,并在许多注释中被null一词所取代。您的困惑来自VB的行为和特性与C#不同,来自其他语言的程序员没有经验,会对结果感到困惑。
正如接受的答案所述,VB认为这个问题是一个字符串比较,因为其中一个操作数是一个字符串。在字符串比较中,VB将Nothing视为空字符串"",根据MSDN

数字比较将Nothing视为0。字符串比较将Nothing视为""(一个空字符串)。

现在,为什么VB会这样做呢?这是因为VB使用Nothing关键字来表示两个不同的事物(类似于它如何使用=运算符来表示两个不同的事物,即赋值和比较)。第一个用法相当于我上面提到的C#中的null。第二个用法相当于C#中的default(T)运算符。与=运算符一样,VB根据上下文知道如何使用Nothing。例如:
在这一行中,VB将Nothing用作null
Console.WriteLine(s Is Nothing) //C#: (s == null)

在这些代码行中,VB使用Nothing作为default(T)来给变量赋予默认值。
Dim s As String = Nothing //C#: string s = default(string);
Dim i As Integer = Nothing //C#: int i = default(int);

最后,当比较不同类型的变量时,VB和C#都会将一个操作数转换为与另一个操作数匹配的类型。例如,如果您比较double和integer值,则VB和C#都将返回true此行:

Console.WriteLine(5.0 = 5) //C#: (5.0 == 5)

然而,VB和C#在类型转换方面有所不同。此外,在VB中,空字符串""和null在字符串比较中被视为相同,但在C#中并非如此。这使得大多数情况下使用VB更容易。因此,您可以像这样轻松测试您的字符串是否没有值:
Console.WriteLine(s = Nothing)
Console.WriteLine(s = "")

两行代码返回的结果相同,因为VB将 Nothing 视为“”进行比较。在C#中,您不能这样做,您必须像这样测试两者:

Console.WriteLine(s == null && s == "")

显然,在这种情况下,VB比C#更容易和更短,这是最常见的情况。然而,这是以失去一些控制为代价的。在不太常见的情况下,当您只想测试空引用时,C#显然更好,因为您仍然可以使用==运算符:

Console.WriteLine(s == null)

在VB中,你不能使用=运算符,而需要使用另一个运算符Is

Console.WriteLine(s Is Nothing)

尽管VB在上一个例子中更容易,但C#更加清晰。因此,从代码清晰度的角度来看,这行代码可以在两种语言中使用,得到相同的结果:

Console.WriteLine(string.IsNullOrEmpty(s))

我不确定 Default(T) 的含义。如果你反汇编 Dim s As String = Nothing,生成的 IL 代码会将 s 设置为 null 引用,正如你所期望的那样 (ldnull, stloc.0)。只有在比较时,它才会通过 Microsoft.VisualBasic.CompilerServices.Operators::CompareObjectEqual 转换为空字符串。 - SSS
@SSS 是的,在 VB 中,将 Nothing 和空字符串 "" 进行字符串比较是一个特殊情况,与 default(T) 没有任何关系。在这种比较中,Nothing 实际上就像是 null。因此,你的最终答案是对这个问题的很好回答。我只想添加一些有用的信息,例如在赋值期间将 Nothing 视为 default(T),以及自动转换会让人们误认为 Nothing 不是 null 的其他特殊情况。实际上它是 null,而 default(T) 行为是次要的使用。 - Racil Hilan

1
在VB中,对象类型不影响其值: - 引用类型等同于null - 值类型等同于默认值;对于可空类型而言,这个默认值是null。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接