C# 为什么不写list.Count.Equals(0)

C# 为什么不写list.Count.Equals(0),c#,C#,你不写信的理由是什么 list.Count.Equals(0) 当你可能写信的时候 list.Count == 0 有技术/语义上的原因吗?两个主要原因是 list.Count==0更容易阅读(最重要) list.Count.Equals(0)速度较慢 我认为对于这个具体案例,两种说法没有区别。因为您正在检查int值的相等性=运算符和等于执行完全相同的操作 但对于其他一些情况,例如对于以下情况,它们可能返回不同的值 Double.NaN == Double.NaN // is false

你不写信的理由是什么

list.Count.Equals(0) 
当你可能写信的时候

list.Count == 0

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

两个主要原因是

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

  • list.Count.Equals(0)速度较慢


  • 我认为对于这个具体案例,两种说法没有区别。因为您正在检查
    int
    值的相等性
    =
    运算符和
    等于执行完全相同的操作

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

    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 
    

    我认为更具可读性

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

    我不是C#专家,所以你最好在这里检查一下如何使它工作。

    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\u 0029:callvirt实例int32类[mscorlib]System.Collections.Generic.List`1::get\u Count()
    IL_002e:stloc.s CS$0$0001
    IL_0030:ldloca.s CS$0$0001
    IL_0032:ldc.i4.0
    IL_0033:调用实例bool[mscorlib]System.Int32::Equals(Int32)
    //Equals(obj int)在内部使用this==obj的方法;
    
    vs

    IL\u 007f:callvirt实例int32类[mscorlib]System.Collections.Generic.List`1::get\u Count()
    IL_0084:ldc.i4.0
    IL_0085:ceq
    
    有人可能会说==运算符更快,因为它使用的指令更少,但没有人真正知道它是如何得到优化的


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

    第二种情况更可读,不是吗?这取决于
    列表
    实际是什么(
    Equals
    可能与
    operator==
    具有不同的覆盖,但这很愚蠢)
    是检查空列表的首选方法。@ArtemKoshelev:这取决于
    列表的实际内容。Count
    的答案表明,这个问题很有可能得到事实和特定专业知识的支持。因此,我投票赞成重新打开它。@ArtemKoshelev-我同意,就性能而言,
    !Any()如果您只有一个
    IEnumerable
    ,则显然首选
    ,如果您只有一个
    ICollection
    ,则很可能首选
    ,但是变量
    列表
    表明他们至少有
    IList
    ,在这种情况下
    计数
    被认为是便宜的,因此这就成了一个品味问题。“愚蠢”是一个极端的判断。Otoh,你的评论确实让我思考为什么我仍然使用“计数=0”。;这实际上只是多年来的一个老习惯;不再合理。你认为它为什么会慢一些?我认为int的运算符重载使用Equals重写。对我来说,原因是Equals用于引用类型,而不是像integer这样的值类型。int上的Equals不会被装箱。@SecurityMatt Equals不需要对象。有两个方法重写;预期为对象,预期为整数。如果使用预期为整数的方法,则不会进行转换。@abatishchev:不会。在C#中,它编译为ADD操作码,然后JIT到处理器上的单个ADD操作。当执行Int==Int时,不会调用任何方法,但如果调用i,则会调用一个方法nt.Equals(0)…-11分钟前的SecurityMatt“==大约快25毫秒”-除非你说总数是多少,否则没有用。如果是100毫秒,那将是非常重要的。如果是10000毫秒,那么没有那么多:)但是
    IsEmpty
    不是一个内置方法。在您所指的答案中,此人将其创建为扩展方法。显然,人们可以创建他们想要的任何扩展方法,但这仍然需要一个问题,即在该扩展方法中放置什么是最好的。。。这就是我们需要回答的问题。
      IL_007f:  callvirt   instance int32 class [mscorlib]System.Collections.Generic.List`1<string>::get_Count()
      IL_0084:  ldc.i4.0
      IL_0085:  ceq