【问题标题】:What is good practice for null reference checks? [duplicate]空参考检查的良好做法是什么? [复制]
【发布时间】:2011-01-31 10:56:12
【问题描述】:

检查对象上的空引用最有效的方法是什么?我见过各种代码示例,它们有不同的检查方式,以下哪一种是最有效的,还是被认为是最佳实践的?

Object.ReferenceEquals(item, null)

item == null

item != null

Object.Equals(item, null)

谢谢

【问题讨论】:

  • 假设其中一个比其他的慢 10 倍,而您使用了它。你会注意到吗?仅当它位于罕见的昂贵热点时。
  • @MikeDunlavey:当然,选择比所提供的任何其他选项慢 10 倍的选项是完全愚蠢的(假设其他选项在语义上是正确的)。如果替代方案是愚蠢的并且不会带来任何额外的好处,那么优化并不是为时过早。
  • @EdS.:也许这是愚蠢和愚蠢的,但人们总是这样做,如果它在性能不是问题的代码中,那真的没问题。每当人们 new 任何事情时,他们都会花费大量的周期,如果他们使用解释性语言,他们会付出 1-2 个数量级的速度比。
  • @MikeDunlavey:人们一直都在做很多愚蠢的事情,但这并不能解决问题。您无法在 C# 中使用 new 进行比较,因为它是强制性的。不了解他们正在编写的代码的含义的开发人员/工程师是不称职的。
  • 我支持那些说要使用 == 和 != 的人。编译器可能会将该语法转换为 Object.Equals(item, null) 或 ReferenceEquals(item, null) 或其他东西(毕竟更改代码是编译器所做的),但除非你已经分析了你的运行,否则清晰是你的首要任务代码并知道您有性能问题

标签: c# performance


【解决方案1】:
  1. Object.ReferenceEquals(item, null) 比较引用并等于item == null
  2. Object.Equals(item, null) 比较引用类型的引用和值类型的按位,但在反射器中它等于 (item == null) || ((item != null && null != null) && item.Equals(null))
  3. item != null 代码并不总是等于!(item == null),但结果当然应该相等。
  4. item == null 代码不等于null == item,它类似于typeof(item).Equals(object)object.Equals(typeof(item)) 方法调用。

它有所不同,因为您可以覆盖 !===Equals。 使用已知实现的方法,null == item 编码更好,但更难阅读。 Object.ReferenceEquals(null, item) 可能会更快,也可能不会。

附:也使用 string.IsNullOrEmpty(item)

【讨论】:

  • null == item更难阅读,在许多 c 风格的语言中,这是一种更好的做法,因为这种习惯消除了在比较时进行赋值的可能性故意的。当然,如果您尝试在条件中进行赋值,C# 编译器会向您咆哮。但我仍然认为这是一个很好的做法。我没有进行基准测试,但在第 4 点中,虽然不完全相同,但比较肯定是等效的,并且执行了所有相同的操作,所以如果存在性能差异,我会感到非常惊讶。
【解决方案2】:

为了与null 进行比较,我总是使用==!=,因为对于null,它应该始终给出与ReferenceEqualsEquals 相同的结果(所以不需要额外的代码)。

编辑:确实,== 可能会被覆盖,从而为null(即true)提供错误的结果,但这意味着覆盖有问题。为了使代码可读,我会坚持使用==!=

【讨论】:

  • -1,并非总是如此。如果这些运算符被重载(当然以毫无意义的方式),它可能与 .ReferenceEquals 不同
  • nawfal,当然你是对的 - 只有在 == 运算符的无意义(不正确)覆盖中才有可能。我宁愿依靠== 不是伪造的,并且能够编写更具可读性的代码(例如null != obj 而不是false == Object.ReferenceEquals(obj, null)
  • 但你永远不知道。并且上面的代码可以压缩成!ReferenceEquals(obj, null),甚至更好的扩展方法。只是说。
  • 这里没有什么大论据,但扩展可能同样是错误的。问题是你在哪里画线。
  • 是的,但我认为扩展方法是安全的,因为您将自定义空检查移动到具有该意图的方法。重载更为常见。我明白你的意思。让我编辑你的帖子以取消我的投票
【解决方案3】:

更新答案

从 C# 7.0 开始,您可以使用:

item is null

应该是最简单最万无一失的方法了。同ReferenceEqualscheck。


旧答案:

1)

Object.ReferenceEquals(item, null)

这是一个好方法。不像我想要的那样简洁,但仍然很棒,并且准确地告诉了你的意图。

2)

item == null

item != null

如果您确定== 和随后的!= 正确重载,这没有任何问题(这是最优雅的)。它很容易编写(重载)错误的相等运算符(并且经常这样做)。但真正的麻烦是当你试图在一个类中重载== 运算符时(让我们说值语义)。 您不能在==since that will cause an infinite recursion 的重载函数中使用== 进行空检查。为了拥有一种一致的风格,我依赖于别的东西。

3)

Object.Equals(item, null)

再次在内部执行ReferenceEquals,所以没有多大意义,但如果它在语义上对您更有意义,那就继续吧。

4)

我的做法是做

(object)item == null

我依赖object 自己的等式运算符,它不会出错。不太可读,所以我只包装了一个自定义扩展方法和一个重载:

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}

这更有意义,因为我需要经常检查DBNulls。所以现在我有一个一致的风格!

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}

(如前所述,不要取消 (object) 强制转换,因为这会在重载 == 时防止无限递归)

此外,约束防止 IsNull 在值类型上。现在就像打电话一样甜蜜

object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error

我还发现 (object)item == nullvery very very slightly faster than Object.ReferenceEquals(item, null)object.Equals(,) ,但前提是它很重要(我目前正在做一些我必须对所有内容进行微优化的事情!)。

要查看有关实施平等检查的完整指南,请参阅What is "Best Practice" For Comparing Two Instances of a Reference Type?

【讨论】:

    【解决方案4】:

    另外,不要忘记 .NET 4.0 中的代码协定!

    System.Diagnostics.Contracts.Contract.Requires(item != null);
    

    这不仅美观而且清晰,而且允许编译时检查。请参阅 msdn 中的 Code Contracts

    【讨论】:

      【解决方案5】:

      ReferenceEquals 等价于(object)o1==(object)o2。如果相等运算符被重载,它可能比o1==o2 更快。 Object.Equals 可能会慢一些。

      ==!= 之间的区别不在于性能,而在于您的程序应该是什么样子。如果 ==!= 运算符重载,它们可能会慢一些。

      但我认为它们之间的性能差异根本不重要。我会选择一个最容易阅读的。这通常是==!=

      如果我抛出异常,我通常使用==,如下所示:

      if(o == null)
        throw new ...;
      

      如果null 导致无操作,那么通常!= 是合适的

      if(x != null)
      {
         ...
      }
      

      【讨论】:

      • 嗯。 ReferenceEquals 等同于 (object)o1==(object)o2 依赖于 System.Object 数据类型的比较运算符进行引用比较的明确知识。当然,也许一个好的程序员应该知道这一点。但它感觉有点“聪明”,因此如果你正在扫描代码以理解它,它就会有点模糊。我这样说并不是不尊重,但只要是合理的,我更倾向于清晰而不是聪明。
      【解决方案6】:

      我总是用

      item != null
      

      但这比阅读更难

      item == null
      

      Object.ReferenceEquals 用于检查两个对象是否是同一个实例。

      【讨论】:

      • 您如何认为!=== 更难阅读?
      • 根据您使用的字体,感叹号不如等号那么明显。例如,这些是更少的像素! than = 例如,如果您在 (!bool) 中使用的比 (bool==false) 更容易错过,这取决于您是否有任何视障人员我想!
      • 如果这曾经对您来说是个问题,听起来您需要在 IDE 中切换字体。
      • 这对我来说不是问题,这是我在阅读有关代码可读性的文章时了解到的。我使用 Droid 字体,如果我无法阅读自己的代码,我会更改它:p code.google.com/webfonts/family?family=Droid+Sans+Mono
      • 我赞成null == item,因为在许多语言中,如果程序员滑倒并说item=null,编译器会很高兴地进行赋值并返回true,而不是执行比较。但是null = item 在每种语言中都是无效的,基本上所有编译器都会捕获它。
      【解决方案7】:

      前两个实际上是相同的。

      然而,最后一个不仅做参考检查,也不应用于空值检查。

      【讨论】:

        猜你喜欢
        • 2023-03-07
        • 1970-01-01
        • 2021-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-09
        • 1970-01-01
        • 2010-12-25
        相关资源
        最近更新 更多