为啥 is 运算符在给定 null 时返回 false?

Posted

技术标签:

【中文标题】为啥 is 运算符在给定 null 时返回 false?【英文标题】:Why does the is operator return false when given null?为什么 is 运算符在给定 null 时返回 false? 【发布时间】:2011-11-30 04:50:27 【问题描述】:

在我看来is 运算符有点不一致。

bool Test()

    // Returns false, but should return true.
    return null is string;

人们期望null 值属于任何引用(或可为空)类型。事实上,C# 语言规范中的某些内容支持这一假设,例如(6.1.6 隐式引用转换):

隐式引用转换是: ... • 从空文字到任何引用类型。

is 运算符的描述(7.10.10 is 运算符)首先说,当存在从 ET 的引用转换时,表达式 (E is T) 将导致 true,但随后作者继续明确排除 Enull 文字或具有 null 值的情况。

他们为什么这样做?在我看来,这似乎违反直觉。

【问题讨论】:

为什么他们明确排除 null 充其量是程序员的一个问题。***.com 我无法撤销我的近距离投票,但这些问题在这里很好:meta.stackexchange.com/questions/36850/… 在java中null typeof Object也返回false 假设null is stringtrue,这意味着nullstring。还假设null is Nullable<int>true,这意味着nullNullable<int>。现在,回答这个问题:null 是什么类型的? @Michael Kjörling:不合逻辑。从上述事实(null 是一个字符串,null 是一个 Nullable)来看,我不应该能够回答这个问题。 【参考方案1】:

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


你正盯着一条空荡荡的车道。

有人问你“你的车道能停一辆本田思域吗?”

是的。可以。

有人将您指向第二条车道。它也是空的。他们问“我车道上的当前内容是否适合您的车道?”

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

有人问你“你的车道上有本田思域吗?”

不,它没有。

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

这不是is 操作员回答的问题。 is 操作员回答的问题是第三个问题。 y is X 不问“yX 类型变量的合法值吗?”它问“y 是对 @ 类型对象的有效引用吗?” 987654333@?" 由于空引用不是对 any 类型的 any 对象的有效引用,因此答案为“否”。那条车道是空的;它不包含本田思域。

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


更深入地了解您的问题:

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

人们会隐含地假设一个类型是一个值的集合,并且值y与一个变量的赋值兼容性类型 X 无非是检查 y 是否是集合 x 的成员

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

如果您对类型理论感兴趣,请查看我最近关于该主题的文章:

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

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

【讨论】:

@Gebb:很高兴为您提供帮助。您可能也会对这篇文章感兴趣:blogs.msdn.com/b/ericlippert/archive/2010/09/16/… Eric 把它变成了一篇博文:ericlippert.com/2013/05/30/what-the-meaning-of-is-is y is X 不问“yX 类型变量的合法值吗?”它询问“y 是对X 类型对象的有效引用吗?”这就是重点!谢谢! 但如果我问y is int?,那么我会问“你的车道上是本田思域还是什么都没有?”。当您的车道空无一人时,为什么答案仍然是否定的?如果您深入了解情况,情况只会变得更糟,因为问题变成了“您的车道上是否有本田思域或标有‘这里没有本田思域’的标志?”。即使您的车道上有上述标志,答案仍然是否定的。 阅读本文时,我感受到了公主新娘的气息。 “显然我不能选择我面前的酒!”【参考方案2】:

我认为null is string 返回 false 非常直观。 Null 没有任何意义,它绝对不是字符串。所以它应该返回false。虽然这是语言设计者做出的选择,但当您考虑 null 的实际含义时,它是一个非常直观的选择。

【讨论】:

+1 因为问题实际上是关于它是否直观而不是质疑OP已经知道的规范。如果你用英文句子“is null a string”问它,答案是否定的,不是,这与“is null assignable to string”不同 null is string 非常直观,(string)null is string 如果您对 C# 中空引用的工作方式不是很熟悉,可能需要暂停一下。【参考方案3】:

null 文字可以分配给 any 引用类型。它本身不是一种类型。它是一个特殊的literal表示一个空引用。

如果is 将在传入null 时返回true,那么您可以使用null 文字做什么?没什么 - 它是null。除了令人困惑的事情之外,它返回true 有什么意义?


不管 - 就直观而言,阅读英文代码并告诉我:

null is string;

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

【讨论】:

没关系,但它也是一个字符串,对吧?但是为什么(null is string) 会返回flase 呢? 我会反过来说。任何引用类型都可以为空。 null 只是 null。 @Oded 那么空值是对象类型的有效值吗?我可以将它分配给这种类型的变量,对吧?所以答案似乎是肯定的,这个值是完全有效的,我的猜测是(null is object) 表达式应该准确地检查这一点。 @Gebb:不要忘记 ValueTypes 也是对象,但不是引用类型。 @Oded:“除了令人困惑的事情之外,它返回 true 的意义何在?”实际上,它会使语言更合乎逻辑。考虑这两点:(1)is操作符检查是否存在引用(我们这里不需要其他类型的转换)转换; (2)null可以转换为任何引用类型。因此(null is T),其中 T 是引用类型应该返回 true。但是不,这里我们有一个明确的例外,这让我感到困惑。【参考方案4】:

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

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

表达式不为空。 表达式可以转换为类型。也就是说, form (type (expression) 将在不引发异常的情况下完成。 有关详细信息,请参阅 7.6.6 转换表达式。

【讨论】:

无论如何文档只说明表达式不能为空(我们已经知道),但它没有说明原因 你为什么要其他方式? @username:这个答案解释了它的机械工作方式,并引用了一个参考资料,它为您提供了一个可以使用的模型。你在这里问宇宙的意义。我想你很幸运,我们的上帝经常光顾;)【参考方案5】:

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

不用说

if (X != null && X is Foo) 

我只能说

if (X is Foo) 

并完成它。

【讨论】:

【参考方案6】:

null

我从您的问题中引用了这一点,因为它似乎触及了问题的核心。 null 不是一个值 - 它是一个值的缺失。 is 对我来说似乎是为了回答这个问题:

如果我将E 转换为T,我会成功获得T 吗?

现在,虽然您可以null 转换为T 没有错误,但在这样做之后,您不要“有一个T" - 你仍然一无所有。所以null不是“是”T,所以is返回false。

【讨论】:

【参考方案7】:

在 Java 中,有一个操作符可以做完全相同的事情,但它的名称要长得多:instanceofnull instanceof String 返回 false 非常直观,因为 null 不是任何事物的实例,更不用说 String。因此,当使用null 时,Java 的版本更直观一些。

但是,当要求查看整个层次结构时,这两个运算符都会返回 true。例如。如果String 的实例是Object。这里是 Java 不太直观(因为一个实例实际上有一个非常特定的类型),而 C# 的 is 更直观(因为每个String 一个Object 深处)。

底线:如果你试图用一个词来描述相当高级的逻辑,你肯定很少有人会这样或那样混淆。似乎大多数人都同意一个含义,而那些不同意的人则不得不调整。

【讨论】:

以上是关于为啥 is 运算符在给定 null 时返回 false?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当@val IS NULL 时SELECT 'A' WHERE @val IN (1, 2, 3, NULL) 不返回值? [复制]

Python - 为啥在这种情况下“is”运算符返回 true? [复制]

为啥 returnValueMap() 返回 NULL

is 和 as 运算符

为啥我的云函数返回带有代码 INTERNAL 的异常,并且详细信息为 null 并带有未处理的错误 TypeError: is not a function

为啥使用 null 函数而不是 == [] 来检查 Haskell 中的空列表?