【问题标题】:Using "is object" instead of "!= null" or Object.ReferenceEquals() [closed]使用“is object”而不是“!= null”或 Object.ReferenceEquals() [关闭]
【发布时间】:2017-10-10 11:49:49
【问题描述】:

C# 没有一个不能重载的专用引用相等运算符,这一直困扰着我。为了测试引用是否为空,我想编写如下代码:

if (thing == null)

但总有这样一个烦人的想法,“如果类重载了 == 运算符怎么办?”。我对类是否认为对象等效于 null 不感兴趣。我对对象 reference 是否为空感兴趣。替代方案似乎正在转换为对象:

if ((object)thing == null)

和 Object.ReferenceEquals():

if (Object.ReferenceEquals(thing, null)) // long form
if (ReferenceEquals(thing, null)) // short form

但是最近一直在写这样的代码:

if (thing is object) // thing != null
if (!(thing is object)) // thing == null

我把它读作“如果事物是​​一个对象”,也就是说它被设置为一个对象。我意识到这不是“is”运算符的目的,但它确实检查空引用并且所有引用类型都从对象继承,所以......为什么不呢?

我发现,至少对我来说,这样的代码更易读,打字也更舒服,特别是因为在我的代码中,肯定情况(事物是对象)比否定情况(!(事物是对象))。

所以我的问题是,有没有我不知道的陷阱或边缘情况?它被认为是不好的做法还是效率低下?是否令人困惑?为什么我从来没有见过这样的代码?

【问题讨论】:

  • 直到现在,我从来没有考虑过 isfalse 返回 null 值,所以我认为这会很混乱。主要是因为一个对象不是一个对象会很奇怪,至少对我来说
  • 我不确定我是否理解为什么你这样做。如果一个对象已经覆盖了 == 以及它与 null 的比较,那么你为什么不直接使用它呢?如果对象实际上是一个空引用,而不是告诉你它相当于空的对象,我想不出任何你想做不同的事情的情况。该课程的作者应该担心它的== null 逻辑是否正确,我不知道你什么时候会决定你知道得更好......
  • @Steven c# 既有值比较,又有参考比较。这是2个不同的东西。这意味着它们相等或不相等并不是那么微不足道。
  • Object.ReferenceEquals 有什么问题?这是惯用的。
  • 这是基于意见的,但我认为您在简洁方面获得的任何优势都会被降低的可读性所抵消,即使仅仅是因为 thing == null 如此无处不在。

标签: c#


【解决方案1】:

if (thing is object)
  ...

你混淆了你想做的事情 - 检查null。目前对您来说可能很明显而且很干净,但可能不会在几个月内(鉴于您已经放弃了这种做法),而且对于其他任何人来说肯定显而易见。如果我遇到这种情况,我就会对作者的意图感到困惑。如果您需要评论来解释您的工作......不要这样做。 (当然,在某些情况下您可以而且应该这样做,但绝对不是像null-check 这样简单的事情。)

最终你会降低你的代码的可维护性,因为理解你的代码总是需要双重考虑。帮自己一个忙,让你的代码尽可能干净,这意味着要诚实地表达你的意图。

【讨论】:

  • So to me, it's clear. 询问接下来遇到的 20 位 C# 开发人员,这些代码的作用。然后问他们if (thing == null)(或ReferenceEquals)做了什么。 我建议他们比前者更快地回答后一个问题。 编程的一部分是坚持普遍接受的做法来减少认知负荷。如果你做“奇怪的事情”,那么当错误发生时,人们会花时间专注于错误的事情。 “那东西很奇怪,我最好检查一下,以防万一。”
  • @Nexus:我必须根据手头的语言规范仔细检查这段代码是否真的与!Object.ReferenceEquals(object, null) 相同,包括值和可空类型。据我所知,确实如此,但我必须检查的事实(作为从 .NET 1.0 出现之日起就有 C# 经验的人)表明这可能不是您想要的成语。 is检查类型 密切相关。它也碰巧检查null 是次要效果,使用它作为主要效果并不明显,至少对我来说不是。
  • And they would be wrong. 他们可能错了,但他们没有错。您正在通过降低整体可维护性和增加认知负荷来解决不存在的(或充其量假设)问题。如果 == 运算符实施不正确,答案是不要像您建议的那样使用 is。这是为了修复错误。或者,只需使用ReferenceEquals 并停止强调它。 或者继续按你的方式做,知道你理解它,未来的开发者可能更难理解。
  • @Nexus:你走错路了——我的意思是is 运算符实现的主要功能,它肯定不会检查nullx is Foo 旨在检查 x 是否属于运行时类型 Foo(或后代)。 null 从未碰巧被视为 Foo 是正确的,但不是大多数人在阅读该声明时最重要的想法。你找到了一种is 的形式,它(有效地)只检查null 很可爱,但是对于不是你的人来说,它并不直观,如果 cmets 有什么可参考的话。
  • 即使这个问题现在被搁置,读起来也很有趣。我不确定我的评论是否对这次对话有任何好处,但正如接下来的 20 位开发人员 mjwills 之一所提到的,我肯定会几乎立即将任何if (thing is object) 代码重构为if (thing == null),因为thing is object 的意图不是立即对读者来说很清楚(而且代码的阅读频率远高于编写频率)。我遇到的大多数初级开发人员都会偶然发现这是做什么的,因此我认为这是一种代码味道。
【解决方案2】:

我只是在寻找一种更易读的形式。

如果您的目标是简洁,那么扩展方法可能是您的最佳选择。

public static class NullExtensions
{
    public static bool ExactlyNull(this object toCheck)
    {
        return ReferenceEquals(toCheck, null);
    }
}

老实说,我只是按原样使用ReferenceEquals。使用这样的扩展方法往往会降低可维护性,并且通常会导致某些工具(例如 Resharper)提供不太有用的“建议”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 2019-10-07
    • 2018-11-25
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多