为什么在VB.NET和C#中检查null值时会有区别?

为什么在VB.NET和C#中检查null值时会有区别?,c#,vb.net,.net-4.0,null,C#,Vb.net,.net 4.0,Null,在这种情况下: 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"); } Dim x作为系统。可为空(十进制)=无 可为空(指十进制)=无 y=5 如果x是

在这种情况下:

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");
}
Dim x作为系统。可为空(十进制)=无
可为空(指十进制)=无
y=5
如果x是y,那么
Console.WriteLine(“真”)
其他的
控制台。WriteLine(“false”)“”可能是
post well帮助您:

如果我没记错的话,VB中的“Nothing”表示“默认值”。对于值类型,这是默认值;对于引用类型,这将是null。因此,不给结构赋值是完全没有问题的。

因为
xy
返回
nothing
,而不是
true
。由于未定义
x
,因此未对其进行定义。(类似于SQL null)

注意:VB.NET
Nothing
C#
null

您还必须比较
可为空(十进制)
的值,前提是它有一个值

因此,上面的VB.NET与此类似(看起来不太正确):

VB.NET和C#.NET是不同的语言,由不同的团队构建,他们对使用做出了不同的假设;在本例中,为空比较的语义

我个人的偏好是VB.NET语义,它本质上赋予NULL语义“我还不知道”。然后将5与“我还不知道”进行比较。自然是“我还不知道”;我是空的。这还有一个额外的优点,即在(大多数,如果不是全部的话)SQL数据库中镜像NULL的行为。正如所解释的,这也是对三值逻辑的更标准的解释(比C#的解释)

C#团队对NULL的含义做出了不同的假设,导致了你表现出的行为差异。PerEricLippert:“我还写了关于VB/VBScript和JScript中null的语义以及”

在任何可能出现空值的环境中,必须认识到排除中间法则(即A或~A在重言式上为真)不再可靠

更新:

bool
(与
bool?
相反)只能取TRUE和FALSE值。然而,NULL的语言实现必须决定NULL如何通过表达式传播。在VB中,表达式
5=null
5null
都返回false。在C#中,可比较的表达式
5==null
5=null
只有第二个[更新的2014-03-02-PG]返回false。然而,在任何支持null的环境中,程序员有义务了解该语言使用的真值表和null传播

更新

Eric Lippert关于语义学的博客文章(在下面的评论中提到)现在位于:

查看生成的(我已将两者转换为C):

C#:

Visual Basic:

[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");
    }
}
您将看到,VisualBasic中的比较返回Nullable(不是bool、false或true!)。而未定义转换为bool则为false


Nothing
与visualbasic中始终为
Nothing
的内容相比,在visualbasic中不为false(与SQL中相同)。

这无疑是VB的一个古怪之处

在VB中,如果要比较两种可为null的类型,应该使用
nullable.Equals()

在您的示例中,应该是:

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

您的VB代码根本不正确-如果您将“xy”更改为“x=y”,结果仍然是“false”。对于可为空的实例,最常见的表达方式是“Not x.Equals(y)”,这将产生与C#中的“x!=y”相同的行为。

这里观察到的问题是更一般问题的特例,也就是说,至少在某些情况下可能有用的不同平等定义的数量超过了表达它们的常用手段的数量。在某些情况下,令人遗憾的是,人们认为,让不同的平等测试方法产生不同的结果是令人困惑的,而让不同形式的平等在可能的情况下产生相同的结果,可以避免这种困惑,这使问题更加严重

事实上,造成混淆的根本原因是一种错误的信念,即不同形式的平等和不平等测试应该产生相同的结果,尽管不同的语义在不同的情况下是有用的。例如,从算术的角度来看,能够将仅在尾随零的数量上不同的
十进制
比较为相等是很有用的。类似地,对于双值,如正零和负零。另一方面,从缓存或实习的角度来看,这种语义可能是致命的。例如,假设有一个
字典
myDict[someDecimal]
应该等于
someDecimal.ToString()
。如果有许多
Decimal
值要转换为字符串,并且期望有许多重复项,那么这样的对象似乎是合理的。不幸的是,如果使用这种缓存来转换12.3m和12.40m,然后再转换12.30m和12.4m,后者的值将产生“12.3”和“12.40”,而不是“12.30”和“12.4”

回到手头的问题,比较可为null的对象是否相等的明智方法不止一种。C#的立场是,它的
==
操作符应该反映
等于的行为。采取的观点是,它的行为应该反映其他一些语言的行为,因为任何想要
Equals
行为的人都可以使用
Equals
。从某种意义上说,正确的解决方案是使用三向“if”构造,并要求如果条件表达式返回三值结果,则代码必须指定在
null
情况下应该发生什么。因为这不是语言的选择,下一个最好的选择就是学习不同的语言是如何工作的,并认识到它们是不同的

因奇登
private static void Main(string[] args)
{
    decimal? x = null;
    decimal? y = null;
    y = 5M;
    decimal? CS$0$0000 = x;
    decimal? CS$0$0001 = y;
    if ((CS$0$0000.GetValueOrDefault() != CS$0$0001.GetValueOrDefault()) ||
        (CS$0$0000.HasValue != CS$0$0001.HasValue))
    {
        Console.WriteLine("true");
    }
    else
    {
        Console.WriteLine("false");
    }
}
[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