16

I was reviewing some code, and I found something that looked like this:

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

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

As far as I know, (IsEditable.Equals(false)) is identical to (IsEditable == false) (and also the same as (!IsEditable)).

Besides personal preference, is there any difference at all between .Equals() and ==, specifically when used to compare bools?

Ryan Kohn
  • 13,079
  • 14
  • 56
  • 81
  • 2
    Just speculation: maybe it was ported from Java where `==` and `.Equals` have different meanings? EDIT: or as Mike Petty pointed out, perhaps it was written by a long-time Java developer who is used to writing `Equals` normally. – Chris Sinclair Nov 28 '12 at 21:39
  • Possible Duplicate: [C#: String.Equals vs. ==](http://stackoverflow.com/q/1659097/299327) – Ryan Gates Nov 28 '12 at 22:06
  • 1
    When `x` is an expression of type (non-nullable) `bool`, I never compare to `true` or `false`. It is easier to use just `x` instead of `x == true` or `x.Equals(true)` or `x != false`, and easier to use `!x` instead of `x == false` or `x.Equals(false)` or `x != true`. And so on. With _two_ non-constant bool expressions, I use the C# built-in operators rather than `Equals`, for example I would use `x == y` or `x != y` (sometimes even `x ^ y`). However with *nullable* booleans, for example `bool? z`, I might use `z == false`. It has the same value as `(z.HasValue && !z.Value)`. – Jeppe Stig Nielsen Jan 10 '14 at 10:26

8 Answers8

12

This is mostly a readability issue. I'd normally use == because that's what I'm used to looking at.

Specifically with bools, you don't have to compare them at all

if(!IsEditable)

will suffice

although, Sometimes I myself do write things like if (val == false) just to be extra sure that i don't misread it when i have to modify the code.

  • I agree with val == false rather than !val as it's much easier to read and when you've been looking at code all day long and are bug hunting your eyes easily miss the ! symbol. Yes, it's more characters to type blah blah, but the compiled version is the same, which is what counts. – Harag Aug 18 '16 at 08:53
12

In fact, for basic types such as int, bool etc. there is a difference between calling Equals() and == due to the fact that the CIL has instructions for handling such types. Calling Equals() forces boxing of the value and making a virtual method call, whereas usage of == leads to usage of a single CIL instruction.

!value and value == false is actually the same, at least in Microsoft's C# compiler bundled with .NET 4.0.

Hence, the comparisons within the following methods

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
}

will compile to to the following CIL instructions:

// 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
Oliver Hanappi
  • 12,046
  • 7
  • 51
  • 68
  • 1
    This potentially impacts performance (and it will almost always be by a negligible amount) but won't ever impact the result of the expression. (Just for those types listed.) – Servy Nov 28 '12 at 22:39
7

The Equals way appears to be significantly slower - roughly 2.7 times in debug mode, and more than seven times in release mode.

Here is my quick and dirty benchmark:

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);
}

Running this produces the following results:

In debug mode

8959
2950
1874

In release mode

5348
751
7

Equals appears to be the slowest. There appears to be little difference between == and !=. However, if (!boolExpr) appears to be the clear winner.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

If you decompile System.Boolean and look at it, It's Equals overloads are defined thus:

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;
}

I would like to think the C# compiler's optimizer and the .Net JIT compiler would be smart enough to inline these, at least for release/optimized compilations, making them exactly the same.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
1

There is a difference - at least in .NET 4.8 - I believe the reason is because of the boxing described in Oliver Hanappi's answer:

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();
}
combatc2
  • 1,215
  • 10
  • 10
-1

In this case, with bools, it doesn't make any difference, however with other built-in non reference types it can.

== allows for conversions of types if it can .Equals won't

Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
  • There are quite a few differences between `operator ==` and `Equals` in the general case, none of which apply to `bool`. The one reason that you gave isn't one of those many reasons; `operator ==` doesn't convert anything. – Servy Nov 28 '12 at 21:47
  • 2
    try doing 1 == 1.0 it will do that comparison just fine, but 1.Equals(1.0) won't... – Keith Nicholas Nov 28 '12 at 21:53
  • `operator ==` isn't converting anything. It's effectively just a method, like any other. It's signature is simply specific enough such that no overload of it will match `1 == 1.0` exactly, it will only match `operator == (double first, double second)` and the compiler will notice that as the closest match, and also that there is an implicit conversion from `int` to `double`. If you used a method with a signature `Equals(double first, double second)` and then called `Equals(1, 1.0)` it would compile and return true. – Servy Nov 28 '12 at 22:02
  • try again, this time when explaining it doesn't convert anything, don't say that it converts something to get its job done. – Keith Nicholas Nov 28 '12 at 22:09
  • `operator ==` *doesn't* convert anything though, that's my point. The C# compiler is doing the conversion as a result of finding the proper overload. If the signature of `Equals` didn't already cover *everything* (being object and object) it would do the same. Using `operator ==` *allows the compiler to perform implicit conversions while `Equals` does not*, but the operator itself still isn't doing any converting. It's an important difference. There is no code, whatsoever, within the definition of `operator ==` that is converting any types. – Servy Nov 28 '12 at 22:12
  • yes... fair enough, I rephrased so not to imply that the operator does it. – Keith Nicholas Nov 28 '12 at 22:15
-1

Take a look at the following quote Taken from here:

The Equals method is just a virtual one defined in System.Object, and overridden by whichever classes choose to do so. The == operator is an operator which can be overloaded by classes, but which usually has identity behaviour.

For reference types where == has not been overloaded, it compares whether two references refer to the same object - which is exactly what the implementation of Equals does in System.Object.

So in short, Equals is really just doing a == anyways.

Robert H
  • 11,520
  • 18
  • 68
  • 110
-1

== is always better than .Equals. In the case of integer comparison, == runs faster than .Equals. In the below test, the elapsed time using == 157, while for .Equals the elapsed time is 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);
    }
}
Ryan Kohn
  • 13,079
  • 14
  • 56
  • 81
pramod
  • 11
  • 2