为什么在 VB.NET 和 C# 中根据值检查 null 会有所不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15524045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is there a difference in checking null against a value in VB.NET and C#?
提问by blindmeis
In VB.NETthis happens:
在VB.NET 中会发生这种情况:
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false") '' <-- I got this. Why?
End If
But in C# this happens:
但是在 C# 中会发生这种情况:
decimal? x = default(decimal?);
decimal? y = default(decimal?);
y = 5;
if (x != y)
{
Debug.WriteLine("true"); // <-- I got this -- I'm with you, C# :)
}
else
{
Debug.WriteLine("false");
}
Why is there a difference?
为什么有区别?
采纳答案by Pieter Geerkens
VB.NET and C#.NET are different languages, built by different teams who have made different assumptions about usage; in this case the semantics of a NULL comparison.
VB.NET 和 C#.NET 是不同的语言,由不同的团队构建,他们对用法做了不同的假设;在这种情况下,NULL 比较的语义。
My personal preference is for the VB.NET semantics, which in essence gives NULL the semantics "I don't know yet". Then the comparison of 5 to "I don't know yet". is naturally "I don't know yet"; ie NULL. This has the additional advantage of mirroring the behaviour of NULL in (most if not all) SQL databases. This is also a more standard (than C#'s) interpretation of three-valued logic, as explained here.
我个人更喜欢 VB.NET 语义,它实质上为 NULL 提供了“我还不知道”的语义。然后将 5 与“我还不知道”进行比较。自然是“我还不知道”;即 NULL。这具有在(大多数,如果不是全部)SQL 数据库中镜像 NULL 行为的额外优势。这也是一个比较标准(比C#的)的三值逻辑的解释,如所解释这里。
The C# team made different assumptions about what NULL means, resulting in the behaviour difference you show. Eric Lippert wrote a blog about the meaning of NULL in C#. Per Eric Lippert: "I also wrote about the semantics of nulls in VB / VBScript and JScript hereand here".
C# 团队对 NULL 的含义做出了不同的假设,从而导致您显示的行为差异。Eric Lippert 写了一篇关于 C# 中 NULL 含义的博客。Per Eric Lippert:“我还在此处和 此处写了有关 VB/VBScript 和 JScript 中空值的语义的文章”。
In any environment in which NULL values are possible, it is imprtant to recognize that the Law of the Excluded Middle (ie that A or ~A is tautologically true) no longer can be relied on.
在任何可能存在 NULL 值的环境中,重要的是要认识到排除中间律(即 A 或 ~A 是同义反复正确的)不再可以依赖。
Update:
更新:
A bool(as opposed to a bool?) can only take the values TRUE and FALSE. However a language implementation of NULL must decide on how NULL propagates through expressions. In VB the expressions 5=nulland 5<>nullBOTH return false. In C#, of the comparable expressions 5==nulland 5!=nullonly the secondfirst [updated 2014-03-02 - PG]returns false. However, in ANY environment that supports null, it is incumbent on the programmer to know the truth tables and null-propagation used by that language.
A bool(与 a 相对bool?)只能取值 TRUE 和 FALSE。然而,NULL 的语言实现必须决定 NULL 如何通过表达式传播。在 VB 中,表达式5=null和5<>nullBOTH 都返回 false。在C#,可比表达式5==null和5!=null仅第二第一[更新2014年3月2日- PG]返回false。但是,在任何支持 null 的环境中,程序员都有责任了解该语言使用的真值表和 null 传播。
回答by Tim Schmelter
Because x <> yreturns Nothinginstead of true. It is simply not defined since xis not defined. (similar to SQL null).
因为x <> y返回Nothing而不是true. 它根本没有定义,因为x没有定义。(类似于 SQL 空值)。
Note: VB.NET Nothing<> C# null.
注意:VB.NET Nothing<> C# null。
You also have to compare the value of a Nullable(Of Decimal)only if it has a value.
您还必须Nullable(Of Decimal)仅在 a 具有值时才比较它的值。
So the VB.NET above compares similar to this(which looks less incorrect):
所以上面的 VB.NET 比较类似于这个(看起来不那么不正确):
If x.HasValue AndAlso y.HasValue AndAlso x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false")
End If
The VB.NET language specification:
VB.NET语言规范:
7.1.1 Nullable Value Types... A nullable value type can contain the same values as the non-nullable version of the type as well as the null value. Thus, for a nullable value type, assigning Nothing to a variable of the type sets the value of the variable to the null value, not the zero value of the value type.
7.1.1 可空值类型... 可空值类型可以包含与该类型的不可空版本相同的值以及空值。因此,对于可空值类型,将 Nothing 分配给该类型的变量会将变量的值设置为空值,而不是该值类型的零值。
For example:
例如:
Dim x As Integer = Nothing
Dim y As Integer? = Nothing
Console.WriteLine(x) ' Prints zero '
Console.WriteLine(y) ' Prints nothing (because the value of y is the null value) '
回答by nothrow
Look at the generated CIL(I've converted both to C#):
查看生成的CIL(我已将两者都转换为 C#):
C#:
C#:
private static void Main(string[] args)
{
decimal? x = null;
decimal? y = null;
y = 5M;
decimal? CS[STAThread]
public static void Main()
{
decimal? x = null;
decimal? y = null;
y = 5M;
bool? VB$LW$t_struct$S3 = new bool?(decimal.Compare(x.GetValueOrDefault(), y.GetValueOrDefault()) != 0);
bool? VB$LW$t_struct$S1 = (x.HasValue & y.HasValue) ? VB$LW$t_struct$S3 : null;
if (VB$LW$t_struct$S1.GetValueOrDefault())
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
}
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If Not Nullable.Equals(x, y) Then
Console.WriteLine("true")
Else
Console.WriteLine("false")
End If
00 = x;
decimal? CS##代码####代码##01 = y;
if ((CS##代码####代码##00.GetValueOrDefault() != CS##代码####代码##01.GetValueOrDefault()) ||
(CS##代码####代码##00.HasValue != CS##代码####代码##01.HasValue))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
}
Visual Basic:
视觉基础:
##代码##You'll see that the comparison in Visual Basic returns Nullable<bool> (not bool, false or true!). And undefined converted to bool is false.
您将看到 Visual Basic 中的比较返回 Nullable<bool>(不是 bool、false 或 true!)。而 undefined 转换为 bool 是假的。
Nothingcompared to whatever is always Nothing, not false in Visual Basic (it is the same as in SQL).
Nothing与NothingVisual Basic 中的always 、 not false相比(它与 SQL 中的相同)。
回答by supercat
The problem that's observed here is a special case of a more general problem, which is that the number of different definitions of equality that may be useful in at least some circumstances exceeds the number of commonly-available means to express them. This problem is in some cases made worse by an unfortunate belief that it is confusing to have different means of testing equality yield different results, and such confusion might be avoided by having the different forms of equality yield the same results whenever possible.
这里观察到的问题是一个更普遍问题的特例,即至少在某些情况下可能有用的平等的不同定义的数量超过了表达它们的常用方法的数量。在某些情况下,这个问题会因令人遗憾的信念而变得更糟,因为人们认为测试相等性的不同方法会产生不同的结果是令人困惑的,并且可以通过让不同形式的相等性尽可能产生相同的结果来避免这种混淆。
In reality, the fundamental cause of confusion is a misguided belief that the different forms of equality and inequality testing should be expected to yield the same result, notwithstanding the fact that different semantics are useful in different circumstances. For example, from an arithmetic standpoint, it's useful to be able to have Decimalwhich differ only in the number of trailing zeroes compare as equal. Likewise for doublevalues like positive zero and negative zero. On the other hand, from a caching or interning standpoint, such semantics can be deadly. Suppose, for example, one had a Dictionary<Decimal, String>such that myDict[someDecimal]should equal someDecimal.ToString(). Such an object would seem reasonable if one had many Decimalvalues that one wanted to convert to string and expected there to be many duplicates. Unfortunately, if used such caching to convert 12.3 m and 12.40 m, followed by 12.30 m and 12.4 m, the latter values would yield "12.3", and "12.40" instead of "12.30" and "12.4".
实际上,混淆的根本原因是一种错误的信念,即认为不同形式的平等和不平等测试应该会产生相同的结果,尽管不同的语义在不同的情况下是有用的。例如,从算术的角度来看,能够将Decimal哪个仅在尾随零的数量上比较为相等是很有用的。同样对于double像正零和负零这样的值。另一方面,从缓存或实习的角度来看,这种语义可能是致命的。举个例子,一个有一个Dictionary<Decimal, String>这样myDict[someDecimal]应该等于someDecimal.ToString()。如果一个对象有很多,这样的对象似乎是合理的Decimal人们想要转换为字符串并期望有很多重复的值。不幸的是,如果使用这样的缓存来转换 12.3 m 和 12.40 m,然后是 12.30 m 和 12.4 m,后者的值将产生“12.3”和“12.40”而不是“12.30”和“12.4”。
Returning to the matter at hand, there is more than one sensible way of comparing nullable objects for equality. C# takes the standpoint that its ==operator should mirror the behavior of Equals. VB.NETtakes the standpoint that its behavior should mirror that of some other languages, since anyone who wants the Equalsbehavior could use Equals. In some sense, the right solution would be to have a three-way "if" construct, and require that if the conditional expression returns a three-valued result, code must specify what should happen in the nullcase. Since that is not an option with languages as they are, the next best alternative is to simply learn how different languages work and recognize that they are not the same.
回到手头的问题,比较可空对象是否相等的明智方法不止一种。C# 认为它的==操作符应该反映Equals. VB.NET的立场是它的行为应该反映其他一些语言的Equals行为,因为任何想要这种行为的人都可以使用Equals. 从某种意义上说,正确的解决方案是使用三向“if”构造,并要求如果条件表达式返回三值结果,则代码必须指定在这种null情况下应该发生什么。由于这不是语言的一种选择,因此下一个最佳选择是简单地了解不同语言的工作方式并认识到它们是不同的。
Incidentally, Visual Basic's "Is" operator, which is lacking in C, can be used to test for whether a nullable object is, in fact, null. While one might reasonably question whether an iftest should accept a Boolean?, having the normal comparison operators return Boolean?rather than Booleanwhen invoked on nullable types is a useful feature. Incidentally, in VB.NET, if one attempts to use the equality operator rather than Is, one will get a warning that the result of the comparison will always be Nothing, and one should use Isif one wants to test if something is null.
顺便说一下,C 中缺少的 Visual Basic 的“Is”运算符可用于测试可空对象实际上是否为空。虽然人们可能会合理地质疑if测试是否应该接受 a Boolean?,但让正常的比较运算符返回Boolean?而不是Boolean在可空类型上调用时是一个有用的功能。顺便提一下,在 VB.NET 中,如果尝试使用相等运算符而不是Is,则会收到警告,比较结果将始终为Nothing,Is如果要测试某些内容是否为空,则应该使用。
回答by evgenyl
May be thispost well help you:
可能 这篇文章对你有帮助:
If I remember correctly, 'Nothing' in VB means "the default value". For a value type, that's the default value, for a reference type, that would be null. Thus, assigning nothing to a struct, is no problem at all.
如果我没记错的话,VB 中的“Nothing”表示“默认值”。对于值类型,这是默认值,对于引用类型,则为 null。因此,不给结构赋值完全没有问题。
回答by Matthew Watson
This is a definite weirdness of VB.
这绝对是 VB 的怪异之处。
In VB, if you want to compare two nullable types, you should use Nullable.Equals().
在 VB 中,如果要比较两个可为 null 的类型,则应使用Nullable.Equals().
In your example, it should be:
在您的示例中,它应该是:
##代码##回答by Dave Doknjas
Your VB code is simply incorrect - if you change the "x <> y" to "x = y" you will still have "false" as the result. The most common way of expression this for nullable instances is "Not x.Equals(y)", and this will yield the same behavior as "x != y" in C#.
您的 VB 代码完全不正确 - 如果您将“x <> y”更改为“x = y”,结果仍然是“false”。对于可空实例,最常见的 this 表达方式是“Not x.Equals(y)”,这将产生与 C# 中的“x != y”相同的行为。

