给定null时,为什么is运算符返回false?

Geb*_*ebb 131 c#

在我看来,is运营商有点不一致.

bool Test()
{
    // Returns false, but should return true.
    return null is string;
}
Run Code Online (Sandbox Code Playgroud)

一个人希望该null值属于任何引用(或可空)类型.事实上,C#语言规范说明了支持这种假设的东西,例如(6.1.6隐式引用转换):

隐式引用转换是:
...
•从null文本到任何引用类型.

说明(7.10.10 is运算符)中的is运营商开始通过说表达(E is T)将导致真正的当从引用转换ET存在的,但随后笔者通过时明确排除的情况下继续Enull文字或具有null价值.

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

Eri*_*ert 194

这个问题是我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中不相同.

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

你称之为"类型"的东西是什么?第一部分

你称之为"类型"的东西是什么?第二部分

  • 但如果我问“y 是 int?”,那么我会问“你的车道上有本田思域还是什么都没有?”。当你的车道空无一人时,为什么答案仍然是否定的?如果你仔细观察引擎盖下的情况,情况只会变得更糟,因为问题变成了“你的车道上有一辆本田思域还是有一个标有‘这里没有本田思域’的标志?”。即使您的车道上有上述标志,答案仍然是否定的。 (2认同)

Ode*_*ded 24

null文字可以被分配给任何引用类型.它本身并不是一种类型.它是一个特殊的文字,表示空引用.

如果将传入一个is将返回的情况,你可以用文字做什么?没什么 - 它是.除了令人困惑的事情之外,返回的重点是什么?truenullnullnulltrue


无论如何 - 就直观性而言,请阅读英文代码并告诉我:

null is string;
Run Code Online (Sandbox Code Playgroud)

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


man*_*lds 24

我认为null is string返回false非常直观.Null意味着什么,它绝对不是一个字符串.所以它应该返回false.虽然它是语言设计者的选择,但当你考虑null的真实世界意义时,它是一个非常直观的选择.

  • +1是因为问题实际上是关于它是否直观,而不是质疑OP已经意识到的规范。如果您以英文句子“ isnull”是一个字符串来问,答案是否定的,不是,这与“ null”是否可分配给“ string”是不同的。 (2认同)

Mis*_*ble 12

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

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

  • 表达式不为空.
  • 表达式可以转换为类型.也就是说,表单(类型(表达式)的强制转换表达式将在不抛出异常的情况下完成.有关更多信息,请参阅7.6.6强制转换表达式.


小智 10

实际上,"null是T == false"可以节省我输入额外的代码:

而不是说

if (X != null && X is Foo) {}
Run Code Online (Sandbox Code Playgroud)

我可以说

if (X is Foo) {}
Run Code Online (Sandbox Code Playgroud)

并完成它.


Aak*_*shM 8

null

我从你的问题中引用了这个,因为它似乎触及了问题的核心.null 不是一个价值 - 它是没有价值的.is我的目的似乎是回答这个问题:

如果我投ET,我会成功获得T吗?

现在,虽然你可以毫无错误null地投射,T 这样做之后你就没有 "拥有T" - 你仍然没有得到任何东西.所以不是null"是"a的情况T,所以is返回false.