关于c#:当给定null时,为什么is运算符返回false?


Why does the is operator return false when given null?

在我看来,is操作符有点不一致。

1
2
3
4
5
bool Test()
{
    // Returns false, but should return true.
    return null is string;
}

我们期望null值属于任何引用(或可以为空)类型。实际上,C语言规范说明了一些支持这个假设的东西,例如(6.1.6隐式引用转换):

The implicit reference conversions are:
...
? From the null literal to any reference-type.

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

他们为什么这么做?在我看来,这是违反直觉的。


这个问题是我2013年5月30日博客的主题。谢谢你的提问!

你盯着一条空车道。

有人问你,"你的车道能容纳本田思域吗?"

对。是的,可以。

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

是的,很明显。两条车道都是空的!所以很明显,其中一个的内容可以与另一个相匹配,因为一开始都没有任何内容。

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

不,不是。

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

这不是is操作员回答的问题。is操作员回答的问题是第三个问题。y is X没有问"yX型变量的合法值吗?"它问"y是否是对X类型对象的有效引用?"由于空引用不是对任何类型对象的有效引用,因此答案是"否"。那条车道是空的,里面没有本田思域。

另一种看问题的方法是,y is X回答问题"如果我说y as X,我会得到一个非空的结果吗?如果y为空,则显然答案为否!

要深入了解您的问题:

One expects that the null value belongs to any reference (or nullable) type

我们可以隐式地假设一个类型是一组值,并且值y与类型x的变量的赋值兼容性仅限于检查y是否是集x的成员。

虽然这是查看类型的一种非常常见的方法,但这不是查看类型的唯一方法,也不是C_查看类型的方法。空引用是C赋值中没有类型的成员,兼容性不仅仅是检查集合是否包含值。仅仅因为空引用的赋值与引用类型x的变量兼容并不意味着空是类型x的成员。"is assignment compatible with"relation和"is a member of type"relation显然有很多重叠,但它们在clr中并不相同。

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

你所说的"类型"是什么?第一部分

你所说的"类型"是什么?第二部分


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

如果is会返回true,那么当null会被传入时,您将如何处理null文本?什么都没有-它是null。它返回true有什么意义,除了混乱的事情?

不管怎样-从直观的角度来看,用英语阅读代码并告诉我:

1
null is string;

当我看到这一点时,似乎是在问一个问题。我的直觉告诉我,不,不是-是nothing


我认为null is string返回错误是非常直观的。空意味着什么都没有,它绝对不是字符串。所以应该返回false。虽然这是语言设计者所做的选择,但当你考虑到"空"的真实含义时,这是一个非常直观的选择。


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

An is expression evaluates to true if both of the following conditions
are met:

  • expression is not null.
  • expression can be cast to type. That is, a cast expression of the
    form (type (expression) will complete without throwing an exception.
    For more information, see 7.6.6 Cast expressions.


实际上,"null is t==false"可以节省我键入额外代码的时间:

而不是说

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

我只能说

1
if (X is Foo) {}

完成它。


the null value

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

If I cast E to T, will I successfully get a T ?

现在,虽然您可以毫无错误地将null强制转换为T,但这样做之后,您就没有"拥有T"—您仍然一无所获。所以不是说null是"T",所以is返回错误。


在Java中有一个操作符做完全相同的事情,但是它有更长的名字:EDCOX1,0。很直观的是,null instanceof String返回false,因为null不是任何东西的实例,更不用说String。因此,当使用EDCOX1(3)时,Java的版本更直观。

但是,当被要求查看整个层次结构时,这两个操作符都返回true。例如,如果String的实例是Object。这里的Java有点不直观(因为一个实例实际上有一个,非常特定的类型),而C的EDCOX1(6)更直观(因为每一个EDCOX1 2)都是一个EDCOX1,5英寸深。

底线:如果你试图用一个词来描述相当高级的逻辑,你肯定会有很少的人困惑,不管是这样还是那样。似乎大多数人都同意一个意思,而那些不同意的人则不得不做出调整。