为什么在C#中不能使用'if (object)'来测试对象是否为空?

8
在C语言中,为了测试指针是否为空,我们可以采用以下方式:
  • if (p != NULL)
  • if (p != 0)
  • if (p)
但是在C#中却没有类似的方法,为什么呢?
if (object)

代替
if (object != null)

8
为什么要费事呢?if (object != null)if (object)更易读且更具描述性。 - Polynomial
16
自从何时起C# == C?仅仅因为C有某个语言特性,并不意味着C#也应该拥有它。 - Oded
6
不用考虑可读性......从类型的角度来看,这是明显错误的。 - Mauricio Scheffer
6
尽管有些人可能持不同意见,但这仍然是一个合理、清晰且有用的问题,不应该被踩。 - Mauricio Scheffer
1
@Otiel:我不是那些给你点踩的人之一,但我认为人们对于这类问题并不感冒:“为什么编程语言 X 没有编程语言 Y 的某个特性?”通常情况下并没有一个好的答案。 - Chris
显示剩余6条评论
8个回答

20

因为这种测试可能导致程序中出现意外的错误,因此他们更喜欢要求布尔表达式明确 (就像 Java 一样),而不是执行 bool 的隐式转换。

这也是为什么你不能在 C# 中使用 int 作为布尔表达式的原因。由于唯一有效的布尔表达式是直接求值为 bool 的表达式,这可防止代码中出现意外的错误,例如旧 C 语言陷阱所示:

if (x = 5)
{ 
   // always true
}

简而言之,这并不是为了支持可读性和明确性而被包含的。是的,在简洁性方面它会有一些轻微的代价,但是减少意外错误的收益远远超过必须在括号内添加!= null的代价...

(当然,你可以创建一个自定义类型到bool的隐式转换作为解决方法,但是你无法将其全局应用于任何对象类型)


if (x = 5) 和这个问题没有任何关系,是吗?这个错误与在那个位置允许赋值有关,与 null 是否可以隐式转换为 false 没有任何关系... 或者 C# 允许在那个位置进行赋值,所以 if (launchMissiles = true) ... 将编译并且会出现可怕的错误吗? - sth
2
@sth: 这是一个组合问题,x = 5 是在C语言中从intbool的隐式转换,这是主要问题。请注意,在C#中,你可以if语句中进行赋值操作,只要它们是bool类型的赋值。就像你说的那样,if (launchMissles = true)。如果最终结果是一个bool类型,它可以合法地用于表达式中。此外,只要评估结果是bool类型,你也可以在if语句中进行赋值操作,比如if ((line = Console.ReadLine()) != null) - James Michael Hare
1
@sth: 不幸的是,赋值语句会评估为它们被赋的值,这使得赋值的结果可以用于比较,并允许我们将表达式链接在一起。因此,唯一真正成为问题的地方就是在if中发生意外的布尔赋值,但这种情况很少见,因为我们通常不说== true== false,而是可以直接省略并测试表达式本身。 - James Michael Hare
1
另外,if (launchMissiles = true) 会给你一个警告。微软不想为核战争负责。 - configurator
@configurator - 真的没错!就像当他们决定,“嘿,也许 format c: 应该确保你真的想这么做…” - James Michael Hare
显示剩余2条评论

14
为什么C#中没有类似的功能呢?
为了使用一个功能,必须首先经历以下几个步骤:
思考 -> 设计 -> 规划 -> 审批 -> 实现 -> 测试 -> 发布
你提到的那个功能已经经过了思考阶段,但它尚未被设计、规划或经过设计委员会的审批,开发团队也没有进行实现和测试。因此,你不能使用这个功能。
如果这并没有回答你的问题,那就“问一个更好的问题”。问一个语言为什么没有某个功能,就像问一个盒子为什么是空的一样。每个空盒子的原因都相同:“因为里面没有东西”。每个不可用的功能之所以不可用,是因为它从未被交付给客户,关于这个问题也没有太多可以说的了。

1
我主要是在询问该功能未被“发布”的原因,以及选择背后的原因。当然,我并不希望得到像“因为没有”这样的答案来回答我的问题“为什么没有呢?”... ;) - Otiel
1
@Otiel:我向您保证,我们不需要“理由”来“不发货”。不发货是“免费的”和“自动的”。我们很少有一个明确的理由不发布一个从未被设计、规定、批准、实施或测试的功能!这个功能从未被设计等事实已经足以解释为什么它不能被发布,您说是吗?我仍然很难理解您在这里真正想问什么。 - Eric Lippert
我同意并理解你的观点,我的担忧只是想了解为什么一个基本且有用的功能(至少在我看来如此)没有被设计、指定...以及在C#中发布。 - Otiel
@Otiel 我猜他们不想在语言中引入布尔比较/对象->null比较的歧义。 - asawyer
@Otiel:原因是语言设计者发现该功能容易引起混淆和错误,不是基本且有用的。 - phoog

9
从技术上讲,它不起作用是因为无法从您的自定义对象类转换为布尔值(boolean),不存在隐式转换。只要提供一个隐式转换运算符,可以检查对象是否为空,就可以使用您的语法:
    public static implicit operator bool(MyType p)
    {
        return (p != null) && (p != 0);
    }

根据Dan Bryant的建议整合:

另一种方法是为您的数据类型实现隐式的“true”和“false”运算符。如果您的类型允许三态评估为bool:true,false和null,则可能需要这样做。在数据库中,这是非常常见的情况,其中null值表示缺失数据。以下是来自MSDN网页的示例:

public static bool operator true(DBBool x)
{
    return x.value > 0;
}

public static bool operator false(DBBool x)
{
    return x.value < 0;
}

好的观点,这可能行得通,但我不建议这样做。 - Scott Chamberlain
我也不想这样做!但有时候需要,就像我在自己的DSL中需要它来允许类似上述的构造。 - Alexander Galkin
无论我们在哲学上是否赞同这样做,一个有效的答案存在,这就是它,所以我为您令人惊叹的回答点赞! - Dracorat
另一个有趣的点是,实际上有一个“true”运算符将被计算这种特定的语法。同样也有一个相等的“false”运算符。http://msdn.microsoft.com/en-us/library/6x6y6z4d%28v=vs.80%29.aspx - Dan Bryant
2
另外,小问题,但在这个特定的例子中,您必须将参数命名为@object,因为“object”是一个保留字。 - Dan Bryant

4
因为编程语言的设计者们就是这样设计的。部分原因是为了防止一些愚蠢的错误,例如:
if (p = 42)

这不是相反吗? C语言的特性难道不是为了避免这些“愚蠢的错误”吗?如果你因为错误而写成 if (p = null),那是因为你想要写成 if (p == null) 或者 if (p != null)。写成 if (p) 才可以避免愚蠢的错误。 - Otiel
@otiel 如果 p 不是布尔类型,这段代码甚至都无法编译通过。不过让我给你一个更好的例子。 - McKay

3

因为一个对象不是指针,而是一个对象。


2
因为这不在C#规范内,编译器无法理解这种表达式。如果你想知道为什么在C#中不使用这种方式,从我的角度来看,在对象上以if(object)的方式检查null完全是不合逻辑的。如果对象是什么?

1

你的示例代码看起来只是因为你的对象被命名为“object”而显得可读。实际上,对象的名称源于它们的用途/功能。如果你的对象被称为“validatedWidget”,那么你的代码将会是这样的

if (validatatedWidget)
{
    // do something
}

这会错误地暗示了某些东西,而实际上:

if (validatedWidget != null)
{
   // do something
}

更加明确,而且几乎没有太多的工作。


0

if语句的语法是:

if(condition)

条件的结果应该是布尔值,即真或假。

因此,我们可以编写任何条件,例如

x = 10;
if(x == 10)

但是,if(object)并没有明确的条件来产生布尔结果。

如果我们写

 boolean object = true;
 if(object)

那么它就完全没问题了。

但是,为了判断任何对象是否为空,我们不能写成if(object),而需要写成if(object == null)或if(object != null),因为这样的条件将产生布尔结果。


这并没有回答为什么不允许的问题。你只是在重申问题的前提(即不允许)。 - jalf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接