当给定null时,为什么is操作符返回false ?

本文关键字:操作符 is 返回 false 为什么 null | 更新日期: 2023-09-27 18:10:16

在我看来,is运算符有点不一致。

bool Test()
{
    // Returns false, but should return true.
    return null is string;
}

期望null值属于任何引用(或可空)类型。事实上,c#语言规范支持这个假设,例如(6.1.6隐式引用转换):

隐式引用转换为:

•从空字面值到任何引用类型。

is操作符的描述(7.10.10 The is操作符)首先指出,当存在从ET的引用转换时,表达式(E is T)将导致true,但随后作者继续明确排除Enull字量或具有null值的情况。

他们为什么那样做?对我来说,这似乎违反直觉。

当给定null时,为什么is操作符返回false ?

这个问题是我2013年5月30日博客的主题。谢谢你的好问题!


你盯着空荡荡的车道看。

有人问你:"你的车道能停得下一辆本田思域吗?"

是的。可以。

有人指给你第二条车道。它也是空的。他们会问:"我车道上的东西能放进你的车道吗?"

是的,很明显。两条车道都是空的!所以很明显,其中一个的内容可以放在另一个中,因为一开始这两个都没有内容。

有人问你:"你的车道上停着一辆本田思域吗?"

不,它没有。

你认为is运算符回答了第二个问题:给定这个值,它是否适合该类型的变量? null引用适合这种类型的变量吗?

这不是is运算符能回答的问题。is运算符回答的问题是第三个问题。y is X不会问" yX类型的变量的合法值吗?",它会问" y是对X类型的对象的有效引用吗?",因为空引用不是对任何类型的任何对象的有效引用,所以答案是"否"。那条车道是空的;里面没有本田思域

另一种看待它的方式是y is X回答了"如果我说y as X,我会得到一个非空结果吗?"如果y为空,很明显答案是否定的!


更深入地看看你的问题:

期望空值属于任何引用(或可空)类型

可以隐式地假设类型是值的集合,并且值y与类型X的变量的赋值兼容性只不过是检查y是否为集合X 的成员。

虽然这是一种非常常见的查看类型的方式,但这并不是查看类型的唯一的方式,也不是c#查看类型的方式。空引用是c#中没有类型的成员;赋值兼容性而不是,只是检查一个集合是否包含值。仅仅因为null引用与引用类型X的变量的赋值兼容并不意味着null是类型X的成员。"与赋值兼容"关系和"是类型的成员"关系显然有很多重叠,但它们在CLR中并不相同。

如果你对类型理论的思考感兴趣,可以看看我最近关于这个主题的文章:

你所谓的"类型"是什么?第一部分

你所谓的"类型"是什么?第二部分

我认为null is string返回false非常直观。Null没有任何意义,而且它绝对不是字符串。所以它应该返回false。虽然这是语言设计者做出的选择,但当您考虑null在现实世界中的含义时,这是一个非常直观的选择。

null字量可以分配给任何引用类型。不是本身的类型。它是一个特殊的字面值表示为空引用。

is将返回true的情况下,当一个null将被传入,你能对null字面量做什么?没什么,是null。除了混淆问题外,返回true的意义是什么?


无论如何-从直观的角度来看,阅读英文代码并告诉我:

null is string;

当我看到它时,它似乎在问问题is "nothing" a string?。我的直觉告诉我,不,它不是——它是nothing

http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx

如果满足以下两个条件,则is表达式的计算结果为true满足:

  • 表达式不为空。
  • 表达式可以强制转换为类型。的强制转换表达式Form (type (expression))完成后不会抛出异常。有关更多信息,请参见7.6.6强制转换表达式。

作为一个实际问题,有"null is T == false"节省了我输入额外的代码:

而不是说

if (X != null && X is Foo) {}

我可以直接写

if (X is Foo) {}

并完成它。

null

我从你的问题中引用了这一点,因为它似乎触及了问题的核心。null 不是一个值——它是没有值。is对我来说似乎是为了回答这个问题:

如果我将E转换为T,我会成功获得T吗?

现在,当你可以null转换为T 而没有错误时,你没有"有一个T"-你仍然什么都没有。因此,null"是"T的情况并非如此,因此is返回false。

在Java中有一个操作符做完全相同的事情,但它有一个更长的名字:instanceof。很直观的是,null instanceof String返回false,因为null不是任何东西的实例,更不用说String了。因此,当使用null时,Java版本更直观一些。

但是,当要求查看整个层次结构时,这两个操作符都返回true。如。如果String的实例是Object。在这里,Java不太直观(因为实例实际上有一个非常具体的类型),而c#的is更直观(因为每个String 都是内部的Object)。

底线:如果你试图用一个词来描述相当高级的逻辑,你肯定会有一些人困惑,这样或那样。似乎大多数人都同意一种意思,而那些不同意的人不得不调整。