使用==或.Equals()进行bool比较

时间:2012-11-28 21:34:53

标签: c#

我正在审核一些代码,我发现了一些看起来像这样的东西:

public class MyClass
{
    public bool IsEditable { get; set; }

    public void HandleInput()
    {
        if (IsEditable.Equals(false))
        {
            //do stuff
        }
    }
}

据我所知,(IsEditable.Equals(false))(IsEditable == false)相同(也与(!IsEditable)相同。)

除了个人偏好之外,.Equals()==之间是否存在任何差异,特别是用于比较bool s 时?

8 个答案:

答案 0 :(得分:10)

这主要是一个可读性问题。我通常会使用==,因为这就是我以前所看到的。

特别是对于bool,你根本不需要比较它们

if(!IsEditable)

就足够了

虽然,有时我自己会写if (val == false)之类的东西,只是为了确保在我必须修改代码时不会误读它。

答案 1 :(得分:8)

事实上,对于intbool等基本类型,由于CIL有说明,因此调用Equals()==之间存在差异用于处理此类型。调用Equals()强制限制值并进行虚拟方法调用,而使用==会导致使用单个CIL指令。

!valuevalue == false实际上是相同的,至少在与.NET 4.0捆绑在一起的Microsoft C#编译器中。

因此,在以下方法中进行比较

public static int CompareWithBoxingAndVirtualMethodCall(bool value)
{
    if (value.Equals(false)) { return 0; } else { return 1; }
}

public static int CompareWithCILInstruction(bool value)
{
    if (value == false) { return 0; } else { return 1; }
    if (!value) { return 0; } else { return 1; } // comparison same as line above
}

将编译为以下CIL指令:

// CompareWithBoxingAndVirtualMethodCall

ldarga.s 'value'
ldc.i4.0
call instance bool [mscorlib]System.Boolean::Equals(bool) // virtual method call
brfalse.s IL_000c // additional boolean comparison, jump for if statement

// CompareWithCILInstruction

ldarg.0
brtrue.s IL_0005 // actual single boolean comparison, jump for if statement

答案 2 :(得分:7)

Equals方式似乎明显变慢 - 在调试模式下大约为2.7倍,在发布模式下大于7倍。

这是我快速而又肮脏的基准:

public static void Main() {
    bool a = bool.Parse("false");
    bool b = bool.Parse("true");
    bool c = bool.Parse("true");
    var sw = new Stopwatch();
    const int Max = 1000000000;
    int count = 0;
    sw.Start();
    // The loop will increment count Max times; let's measure how long it takes
    for (int i = 0; i != Max; i++) {
        count++;
    }
    sw.Stop();
    var baseTime = sw.ElapsedMilliseconds;
    sw.Start();
    count = 0;
    for (int i = 0; i != Max; i++) {
        if (a.Equals(c)) count++;
        if (b.Equals(c)) count++;
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds - baseTime);
    sw.Reset();
    count = 0;
    sw.Start();
    for (int i = 0; i != Max; i++) {
        if (a==c) count++;
        if (b==c) count++;
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds - baseTime);
    sw.Reset();
    count = 0;
    sw.Start();
    for (int i = 0; i != Max; i++) {
        if (!a) count++;
        if (!b) count++;
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds - baseTime);
}

运行它会产生以下结果:

在调试模式下

8959
2950
1874

在发布模式

5348
751
7

Equals似乎是最慢的。 ==!=之间似乎没有什么区别。但是,if (!boolExpr)似乎是明显的赢家。

答案 3 :(得分:2)

如果您反编译System.Boolean并查看它,那么定义它的Equals重载:

public override bool Equals(object obj)
{
  if (!(obj is bool))
    return false;
  else
    return this == (bool) obj;
}

public bool Equals(bool obj)
{
  return this == obj;
}

我想C#编译器的优化器和.Net JIT编译器足够聪明,可以内联这些,至少对于发布/优化的编译,使它们完全相同。

答案 4 :(得分:1)

有一个区别-至少在.NET 4.8中-我认为原因是由于Oliver Hanappi's答案中所述的拳击:

static void Main(string[] args)
{
     object lhs = true;
     object rhs = true;
 
     Console.WriteLine($"Are Equal - {(lhs == rhs ? "Yes" : "No")}"); // Outputs no
     Console.WriteLine($"Are Equal - {(lhs.Equals(rhs) ? "Yes" : "No")}"); // Outputs yes
     Console.ReadLine();
}

答案 5 :(得分:-1)

在这种情况下,使用bools,它没有任何区别,但是对于其他内置的非引用类型,它可以。

如果==不能

,则

.Equals允许转换类型

答案 6 :(得分:-1)

请查看以下引用Taken from here

  

Equals方法只是System.Object中定义的虚拟方法   被任何一个选择这样做的课程所覆盖。 ==运算符是一个   运算符,可以通过类重载,但通常具有   身份行为。

     

对于尚未超载的参考类型,进行比较   两个引用是否引用同一个对象 - 这是确切的   Equals在System.Object中的实现。

简而言之,Equals实际上只是做了==。

答案 7 :(得分:-1)

==始终优于.Equals。在整数比较的情况下,==的运行速度比.Equals快。在下面的测试中,使用== 157的经过时间,而对于.Equals经过的时间是230。

class Program
 {        
   static void Main(string[] args)
    {

        Program programObj = new Program();
            programObj.mymethod();
            programObj.mynextmethod();

    }
    void mynextmethod()
    {
        var watch = Stopwatch.StartNew();

        for (int i = 0; i < 60000000; i++)
        {
            int j = 0;
            if (i.Equals(j))

                j = j + 1;
        }
        watch.Stop();
        var elapsedMs = watch.ElapsedMilliseconds;
        Console.WriteLine("Time take in method" + elapsedMs);


        Console.ReadLine();
    }
    void mymethod()
    {
        var watch = Stopwatch.StartNew();

        for (int i = 0; i < 60000000; i++)
        {
            int j = 0;
            if (i == j)

                j = j + 1;
        }
        watch.Stop();
        var elapsedMs = watch.ElapsedMilliseconds;
        Console.WriteLine("Time take in method" + elapsedMs);
    }
}