当给定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操作符)首先指出,当存在从E
到T
的引用转换时,表达式(E is T)
将导致true,但随后作者继续明确排除E
是null
字量或具有null
值的情况。
他们为什么那样做?对我来说,这似乎违反直觉。
这个问题是我2013年5月30日博客的主题。谢谢你的好问题!
你盯着空荡荡的车道看。
有人问你:"你的车道能停得下一辆本田思域吗?"是的。可以。
有人指给你第二条车道。它也是空的。他们会问:"我车道上的东西能放进你的车道吗?"
是的,很明显。两条车道都是空的!所以很明显,其中一个的内容可以放在另一个中,因为一开始这两个都没有内容。
有人问你:"你的车道上停着一辆本田思域吗?"不,它没有。
你认为is
运算符回答了第二个问题:给定这个值,它是否适合该类型的变量? null引用适合这种类型的变量吗?
这不是is
运算符能回答的问题。is
运算符回答的问题是第三个问题。y is X
不会问" y
是X
类型的变量的合法值吗?",它会问" 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
)。
底线:如果你试图用一个词来描述相当高级的逻辑,你肯定会有一些人困惑,这样或那样。似乎大多数人都同意一种意思,而那些不同意的人不得不调整。