ChatGPT解决这个技术问题 Extra ChatGPT

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

c#

在我看来,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 充其量是程序员的一个问题。stackoverflow.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)来看,我不应该能够回答这个问题。

b
bjan

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

你盯着空荡荡的车道。

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

是的。是的,它可以。

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

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

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

不,不是的。

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

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

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

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

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

有人会隐含地假设一个类型是一组值,并且值 y 与类型 X 的变量的赋值兼容性只不过是检查 y 是否是集合 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


@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?,那么我会问“你的车道是否包含本田思域或什么都没有?”。当您的车道空无一人时,为什么答案仍然是否定的?如果您深入了解情况,情况只会变得更糟,因为问题变成了“您的车道上是否有本田思域或标有‘这里没有本田思域’的标志?”。即使您的车道上有上述标志,答案仍然是否定的。
在阅读本文时,我得到了公主新娘的感觉。 “显然我不能选择我面前的酒!”
m
manojlds

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


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

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

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

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

null is string;

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


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

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

如果满足以下两个条件,则 is 表达式的计算结果为 true:表达式不为空。表达式可以转换为类型。也就是说,(type (expression) 形式的强制转换表达式将在不抛出异常的情况下完成。有关更多信息,请参阅 7.6.6 强制转换表达式。


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

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

而不是不得不说

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

我只能说

if (X is Foo) {}

并完成它。


A
AakashM

空值

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

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

现在,虽然您可以null 转换为 T没有错误,但在这样做之后,您“有一个 T “——你还是一无所有。因此,null 并非“是”T,因此 is 返回 false。


A
Agent_L

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

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

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