为什么is运算符在给定null时返回false?
在我看来,运算符有点不一致。
bool Test() { // Returns false, but should return true. return null is string; }
人们期望null
值属于任何引用(或可空)types。 事实上,C#语言规范说明了一些支持这个假设的东西,例如(6.1.6隐式引用转换):
隐含的参考转换是:
…
•从null文字到任何引用types。
is运算符的描述(7.10.10 is运算符)首先表示当E
到T
的引用转换存在时,expression式(E is T)
将导致真实,但是作者通过明确排除该情况继续当E
是null
文字或有一个null
值。
他们为什么这样做? 对我来说,这似乎违反直觉。
这个问题是我的博客在2013年5月30日的主题 。 感谢您的好问题!
你正盯着一个空的车道。
有人问你:“你的车道可以放一辆本田思域?
是。 是的,它可以。
有人在第二个车道指向你。 它也是空的。 他们问:“我的车道上目前的内容是否适合你的车道?”
是的,显然。 两车道都是空的! 所以很明显,一个人的内容可以放在另一个人的内部,因为没有任何内容。
有人问你:“你的车道是否有本田思域?
不,不是的。
你认为is
运算符回答第二个问题: 给定这个值,它是否适合于这种types的variables? 空引用是否适合这种types的variables? 是的,它确实。
这不是运营商回答的问题。 运营商回答的问题是第三个问题。 y is X
不问“ 是一个X
types的variables的合法值吗? ”它问“ 是一个X
types的对象的有效引用吗? ”由于空引用不是任何对象的有效引用types,答案是“否”。 那条车道是空的 它不包含本田思域。
另一种看待它的方法是y is X
回答“如果我把y as X
表示y as X
,我会得到一个非空的结果吗?如果y为空,那么答案显然是否定的!
在你的问题上稍微深入一点:
人们期望空值属于任何引用(或可空)types
我们可以隐式地假设一个types是一组值 ,并且值y和variablestypesX的赋值兼容性不过是检查y是否是set x的成员 。
虽然这是查看types的一种非常常见的方式,但这不是查看types的唯一方式,也不是C#查看types的方式。 空引用是C#中没有types的成员; 赋值兼容性不仅仅是检查一个集合是否包含一个值。 仅仅因为一个空引用是与引用typesX的variables兼容的 ,并不意味着null是typesX的成员。“赋值兼容”关系和“是types成员”关系显然有很多重叠,但在CLR中它们并不相同。
如果关于types理论的思考关注你,请查看我最近关于这个主题的文章:
你称之为“types”是什么东西? 第一部分
你称之为“types”是什么东西? 第二部分
null
文字可以被分配给任何引用types。 它本身不是一种types。 它是一个特殊的文字 , 代表一个空引用。
在传递null
的情况下返回true
的情况下,你能用null
字符做些什么? 没有 – 它是null
。 除了混淆的事情之外,什么才能回归true
呢?
无论如何 – 就直觉来讲,用英文阅读代码告诉我:
null is string;
当我看到这个问题的时候,似乎是在问这个问题is "nothing" a string?
。 我的直觉告诉我,不,不是 – nothing
。
我认为null is string
返回false是非常直观的。 Null意味着什么,它绝对不是一个string。 所以它应该返回false。 虽然这是语言devise者所做的select,但是当您考虑null的真实世界含义时,这是一个非常直观的select。
http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx
如果满足以下两个条件,则expression式的计算结果为true:
- expression式不为空。
- expression式可以转换为types。 也就是说,表单(expression式)的强制转换expression式将会在不抛出exception的情况下完成,更多信息请参见7.6.6 Castexpression式。
作为一个实际的问题,“null是T ==假”节省我input额外的代码:
而不必说
if (X != null && X is Foo) {}
我可以说
if (X is Foo) {}
并完成它。
null
值
我已经从你的问题中引用了这个,因为它似乎成了问题的核心。 null
不是一个值 – 这是没有价值。 对我来说,目的似乎是回答这个问题:
如果我把
E
投给T
,我会成功拿到T
吗?
现在,虽然你可以 没有错误地将T
施加到T
,但是在这样做之后你不会 “有T
” – 你什么都没有。 所以不是null
“是”一个T
,所以is
返回false。
在Java中,有一个操作符完全相同,但名称更长: instanceof
。 这非常直观, null instanceof String
返回false,因为null不是任何东西的实例,更不用说String
。 所以,使用null
,Java的版本更直观一些。
但是,当要求查看整个层次结构时,这两个操作符都会返回true。 例如。 如果String
实例是一个Object
。 在这里,Java不那么直观(因为一个实例实际上有一个非常具体的types),而C#则更直观(因为每个String
都是内部深处的Object
)。
底线:如果你试图用一个词来形容非常先进的逻辑,你肯定会有这样那样的困惑。 看来大多数人都同意了一个意思,那些不同意的人不得不调整。