在我看来,is
运算符有点不一致。
bool Test()
{
// Returns false, but should return true.
return null is string;
}
我们期望null
值属于任何引用(或可空)类型。事实上,C#语言规范说明了支持这种假设的东西,例如(6.1.6隐式参考转换):
隐式参考转换是:
...... •从null文字到任何引用类型。
is
运算符的说明(7.10.10 is运算符)首先说当从(E is T)
到{{1}的引用转换时,表达式E
将为true存在,但随后作者继续明确排除T
为E
字面值或null
值的情况。
为什么他们这样做?对我而言似乎违反直觉。
答案 0 :(得分:186)
这个问题是subject of my blog on May 30th 2013。谢谢你提出的好问题!
有人问你“你的车道可以装一辆本田思域吗?”
是。是的,它可以。
有人指着你在第二个车道。它也是空的。他们问:“我的车道的当前内容能否适合您的车道?”
是的,很明显。两条车道都是空的!很明显,一个人的内容可以适合另一个,因为首先没有任何内容。
有人问你“你的车道是否包含一辆本田思域?”
不,它没有。
您认为is
运算符会回答第二个问题:给定此值,它是否适合该类型的变量? null引用是否适合变量这个类型?是的确如此。
这不是is
运营商回答的问题。 is
运算符回答的问题是第三个问题。 y is X
不会问“ y
是X
类型变量的合法值吗?”它询问“是y
a对X
类型的对象的有效引用?“由于空引用不是对任何类型的任何对象的有效引用,因此答案没有”。那条车道是空的;它不包含本田思域。
另一种看待它的方法是y is X
回答问题“如果我说y as X
,我会得到非空结果吗?如果y为空,显然答案是否定的! / p>
要更深入地了解您的问题:
我们期望null值属于任何引用(或可为空)类型
可以隐含地假设类型是一组值,而赋值兼容性的值为y,其变量为类型X只是检查y是否是set x 的成员。
虽然这是查看类型的一种非常常见的方式,但这不是唯一查看类型的方式,而不是C#查看类型的方式。空引用是C#中没有类型的成员; 赋值兼容性 不仅检查集合以查看它是否包含值。仅仅因为空引用赋值兼容与引用类型X的变量并不意味着null是类型X的成员。“是与”关系兼容的赋值,“是类型的成员“关系显然有很多重叠,但它们在CLR中并不相同。
如果关于类型理论的思考对你感兴趣,请查看我最近关于这个主题的文章:
答案 1 :(得分:24)
可以将null
字面值分配给任何引用类型。 不本身就是一种类型。这是一个特殊的文字,代表一个空引用。
如果is
传入true
时null
会返回null
,那么您可以使用null
文字做什么?没什么 - 它是true
。除了令人困惑的事情之外,它返回null is string;
会有什么意义?
无论如何 - 就直观性而言,请阅读英文代码并告诉我:
is "nothing" a string?
当我看到它时,似乎在问nothing
这个问题。我的直觉告诉我,不,它不是 - 它是{{1}}。
答案 2 :(得分:23)
我认为null is string
返回false非常直观。 Null意味着什么,它绝对不是一个字符串。所以它应该返回false。虽然它是语言设计者的选择,但当你考虑到null的真实世界意义时,它是一个非常直观的选择。
答案 3 :(得分:11)
http://msdn.microsoft.com/en-us/library/scekt9xw%28v=vs.71%29.aspx
如果同时满足以下两个条件,则表达式的计算结果为true 满足:
- 表达式不为空。
- 表达式可以转换为类型。也就是说,表达了 form(type(表达式)将完成而不会抛出异常。 有关更多信息,请参见7.6.6转换表达式。
答案 4 :(得分:10)
实际上," null是T == false"节省我输入额外的代码:
而不是说
if (X != null && X is Foo) {}
我可以说
if (X is Foo) {}
并完成它。
答案 5 :(得分:8)
null
值
我从你的问题中引用了这个,因为它似乎触及了问题的核心。 null
不是值 - 它是缺少值。我is
的目的似乎是回答这个问题:
如果我将
E
投放到T
,我会成功获得T
吗?
现在,当可以将null
强制转换为T
而不会出现错误时, >“有一个T
” - 你什么都没有。因此,null
“不是”T
,因此is
返回false。
答案 6 :(得分:3)
在Java中,有一个运算符完全相同,但名称更长:instanceof
。那里null instanceof String
返回false非常直观,因为null不是任何事物的实例,更不是String
。因此,当使用null
时,Java的版本更直观一些。
但是,当要求查看整个层次结构时,这两个运算符都返回true。例如。如果String
的实例是Object
。而且这里的Java不那么直观(因为实例实际上有一个非常特定的类型)而C#的is
更直观(因为每个String
一个{{1深入内部)。
结论:如果你试图在一个单词中描述非常高级的逻辑,那么你很少会有这样或那样的人混淆。似乎大多数人都同意一个意思而那些不同意的人必须进行调整。