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

时间:2011-10-03 20:01:49

标签: c#

在我看来,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存在,但随后作者继续明确排除TE字面值或null值的情况。

为什么他们这样做?对我而言似乎违反直觉。

7 个答案:

答案 0 :(得分:186)

这个问题是subject of my blog on May 30th 2013。谢谢你提出的好问题!


你正盯着一条空车道。

有人问你“你的车道可以装一辆本田思域吗?”

是。是的,它可以。

有人指着你在第二个车道。它也是空的。他们问:“我的车道的当前内容能否适合您的车道?”

是的,很明显。两条车道都是空的!很明显,一个人的内容可以适合另一个,因为首先没有任何内容。

有人问你“你的车道是否包含一辆本田思域?”

不,它没有。

您认为is运算符会回答第二个问题:给定此值,它是否适合该类型的变量? null引用是否适合变量这个类型?是的确如此。

这不是is运营商回答的问题。 is运算符回答的问题是第三个问题。 y is X不会问“ yX类型变量的合法值吗?”它询问“y a对X类型的对象的有效引用?“由于空引用不是对任何类型的任何对象的有效引用,因此答案没有”。那条车道是空的;它不包含本田思域。

另一种看待它的方法是y is X回答问题“如果我说y as X,我会得到非空结果吗?如果y为空,显然答案是否定的! / p>


要更深入地了解您的问题:

  

我们期望null值属于任何引用(或可为空)类型

可以隐含地假设类型是一组,而赋值兼容性的值为y,其变量为类型X只是检查y是否是set x 的成员。

虽然这是查看类型的一种非常常见的方式,但这不是唯一查看类型的方式,而不是C#查看类型的方式。空引用是C#中没有类型的成员; 赋值兼容性 仅检查集合以查看它是否包含值。仅仅因为空引用赋值兼容与引用类型X的变量并不意味着null是类型X的成员。“是与”关系兼容的赋值,“是类型的成员“关系显然有很多重叠,但它们在CLR中并不相同。

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

What is this thing you call a "type"? Part one

What is this thing you call a "type"? Part Two

答案 1 :(得分:24)

可以将null字面值分配给任何引用类型。 本身就是一种类型。这是一个特殊的文字代表一个空引用。

如果is传入truenull会返回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深入内部)。

结论:如果你试图在一个单词中描述非常高级的逻辑,那么你很少会有这样或那样的人混淆。似乎大多数人都同意一个意思而那些不同意的人必须进行调整。