[英]Why does the is operator return false when given null?
在我看来, is
运算符有点不一致。
bool Test()
{
// Returns false, but should return true.
return null is string;
}
一个人期望null
值属于任何引用(或可空)类型。 事实上,C#语言规范说明了支持这种假设的东西,例如(6.1.6隐式引用转换):
隐式引用转换是:
...
•从null文字到任何引用类型。
说明(7.10.10 is运算符)的is
通过说表达式运算符开始(E is T)
将导致真正的当从引用转换E
到T
存在,但随后笔者通过明确排除的情况下继续当E
是null
文字或具有null
值时。
他们为什么这样做? 这对我来说似乎违反直觉。
这个问题是我2013年5月30日博客的主题 。 谢谢你这个好问题!
你正盯着一条空车道。
有人问你“你的车道可以装一辆本田思域吗?”
是。 是的,它可以。
有人指着你在第二个车道。 它也是空的。 他们问:“我的车道的当前内容能否适合您的车道?”
是的,很明显。 两条车道都是空的! 很明显,一个人的内容可以适合另一个,因为首先没有任何内容。
有人问你“你的车道是否包含一辆本田思域?”
不,不是的。
您认为is
运算符回答了第二个问题: 给定此值,它是否适合该类型的变量? null引用是否适合此类型的变量? 是的,它确实。
这不是问题的is
运营商的答案。 现在的问题是, is
运营商的答案是第三个问题。 y is X
不问“ 是y
类型的变量的合法值X
?”这问“ 是y
至类型的对象的有效引用X
?”由于空引用不是任何 任何对象的有效引用类型,答案是“不”。 那条车道是空的; 它不包含本田思域。
另一种看待它的方法是y is X
回答问题“如果我说y as X
,我会得到非空结果吗?如果y为空,显然答案是否定的!
要更深入地了解您的问题:
一个人期望null值属于任何引用(或可空)类型
可以隐含地假设类型是一组值 ,并且值y与类型X的变量的赋值兼容性仅仅是检查y是否是集合x的成员 。
虽然这是查看类型的一种非常常见的方式,但这不是查看类型的唯一方法,而且它不是C#查看类型的方式。 空引用是C#中没有类型的成员; 分配兼容性 不仅仅检查组,看它是否包含一个值。 仅仅因为null引用是赋值与引用类型X的变量兼容并不意味着null是X类型的成员。“赋值与”关系兼容并且“是类型的成员”关系显然有很多重叠,但它们在CLR中不相同。
如果关于类型理论的思考对你感兴趣,请查看我最近关于这个主题的文章:
可以将null
文本分配给任何引用类型。 它本身并不是一种类型。 它是一个特殊的文字 , 表示空引用。
在这种情况下is
将返回true
当null
将被传递中,你将能够用做null
的文字? 没什么 - 它是null
。 除了令人困惑的事情之外,它会回归true
的重点是什么?
无论如何 - 就直观性而言,请阅读英文代码并告诉我:
null is string;
当我看到它时,它似乎在问这个问题is "nothing" a string?
。 我的直觉告诉我,不,它不是 - 它nothing
。
我认为null is string
返回false是非常直观的。 Null意味着什么,它绝对不是一个字符串。 所以它应该返回false。 虽然它是语言设计者的选择,但当你考虑null的真实世界意义时,它是一个非常直观的选择。
http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx
如果满足以下两个条件,则表达式的计算结果为true:
- 表达式不为空。
- 表达式可以转换为类型。 也就是说,表单的类型(表达式)将在不抛出异常的情况下完成。有关更多信息,请参阅7.6.6 Cast表达式。
实际上,“null是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
内心深处)。
一句话:如果你试图用一个词来描述非常高级的逻辑,那么你很少会有这样或那样的人混淆。 似乎大多数人都同意一个意思而那些不同意的人不得不进行调整。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.