【问题标题】:Why should I not write list.Count.Equals(0)为什么我不应该写 list.Count.Equals(0)
【发布时间】:2013-02-15 07:59:31
【问题描述】:

你不写的理由是什么

list.Count.Equals(0) 

你可能会写

list.Count == 0

有技术/语义上的原因吗?

【问题讨论】:

  • 第二种情况更具可读性,不是吗?
  • 这取决于list 实际上是什么(Equals 可能与operator== 有不同的覆盖,但这很愚蠢)。一般来说,list.Any() 是检查空列表的首选方式。
  • @ArtemKoshelev:这取决于list.Count 实际上是什么。
  • 正如daryal 的回答所示,这个问题可以很好地得到事实和专业知识的支持。因此,我投票支持重新开放它。
  • @ArtemKoshelev - 我同意,就性能而言,如果你只有一个 IEnumerable!Any() 显然是首选,如果你只有一个 ICollection,则可能是首选,但是变量list 建议他们至少有 IList,在这种情况下,Count 被认为很便宜,所以它成为一个品味问题。 “愚蠢”是一种极端的判断。 OTOH,您的评论确实让我考虑了为什么我仍然使用“Count == 0”;这实际上只是多年老派编程的一种习惯;不再合理。

标签: c#


【解决方案1】:

我认为对于这种特定情况,两个陈述之间没有区别。由于您正在检查 int 值的相等性; == 运算符和 Equals 执行完全相同的操作。

但对于其他一些情况,例如下面的情况,它们可能返回不同的值;

Double.NaN == Double.NaN // is false
Double.NaN.Equals(Double.NaN) // is true

通常,对于值类型,您可以使用==;但如果是引用类型,最好使用Equals

对于int,下面显示了一个样本的反汇编;生成的汇编代码不同,因此预期性能会有所不同;

            int a = 10;
00000080  mov         dword ptr [ebp-40h],0Ah 
                int b = 9;
00000087  mov         dword ptr [ebp-44h],9 

                bool x = a == b;
0000008e  mov         eax,dword ptr [ebp-40h] 
00000091  cmp         eax,dword ptr [ebp-44h] 
00000094  sete        al 
00000097  movzx       eax,al 
0000009a  mov         dword ptr [ebp-48h],eax 
                bool y = a.Equals(b);
0000009d  lea         ecx,[ebp-40h] 
000000a0  mov         edx,dword ptr [ebp-44h] 
000000a3  call        6B8803C0 
000000a8  mov         dword ptr [ebp-60h],eax 
000000ab  movzx       eax,byte ptr [ebp-60h] 
000000af  mov         dword ptr [ebp-4Ch],eax 

【讨论】:

    【解决方案2】:

    两个主要原因是

    1. list.Count == 0 更容易阅读(最重要)

    2. list.Count.Equals(0) 比较慢

    【讨论】:

    • 为什么你认为它更慢?我认为 int 的运算符重载使用 Equals 覆盖。
    • 对我来说,equals 的原因是引用类型而不是值类型,如整数。
    • int 上的等于不会被装箱。
    • @SecurityMatt Equals 确实也不需要对象。有两种方法覆盖;期望一个对象并期望一个整数。如果采用期望整数的方法,则不会进行转换。
    • @abatishchev:没有。在 C# 中,它编译为 ADD 操作码,然后在处理器上跳转到单个 ADD 操作。执行 Int == Int 时不会调用任何方法,但如果调用 int.Equals(0) 则会调用方法。 . – SecurityMatt 11 分钟前
    【解决方案3】:

    list.Count == 0 具有更好的可读性和更短的 imo。如果性能可以忽略不计,请始终使用更具可读性并以最清晰的方式显示意图的内容。

    至于技术原因:如果比较两个生成的 IL 序列。

      IL_0029:  callvirt   instance int32 class [mscorlib]System.Collections.Generic.List`1<string>::get_Count()
      IL_002e:  stloc.s    CS$0$0001
      IL_0030:  ldloca.s   CS$0$0001
      IL_0032:  ldc.i4.0
      IL_0033:  call       instance bool [mscorlib]System.Int32::Equals(int32) 
      // Equals(obj int) internally uses the method this == obj;
    

    对比

      IL_007f:  callvirt   instance int32 class [mscorlib]System.Collections.Generic.List`1<string>::get_Count()
      IL_0084:  ldc.i4.0
      IL_0085:  ceq
    

    有人可能会争辩说 == 运算符更快,因为它使用的指令更少,但没有人真正知道它是如何得到优化的。

    使用 JIT 预热和首先调用的不同序列运行快速基准测试,您会注意到(至少在我的机器上)在超过 100000000 个元素的迭代中,== 快了大约 25 毫秒。

    【讨论】:

    • "== 大约快 25 毫秒" - 除非你说总数是多少,否则没用。如果超过 100 毫秒,那将非常重要。如果超过 10000 毫秒,则不是那么多:)
    【解决方案4】:

    我认为更具可读性

    if (list.IsEmpty()) { ... } 
    

    我不是 C# 专家,所以你最好在这里查看Recommended way to check if a sequence is empty 如何使它工作。

    【讨论】:

    • 但是IsEmpty 不是内置方法。在您所指的答案中,该人 创建 作为扩展方法。显然,人们可以创建他们想要的任何扩展方法,但这仍然会引发一个问题,即最好在该扩展方法中放置什么......这是需要在这个问题中回答的问题。
    猜你喜欢
    • 2019-03-18
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 2012-10-23
    • 2010-12-22
    • 2010-10-07
    相关资源
    最近更新 更多