-1

I'm using a function that returns whether two values are equal/not equal. It takes in two anonymous objects and returns a string based on whether they're equal or not. When I pass two equal integers, such as "2" and "2", the function equates them as not equal.

public string Assert(bool equals, object obj1, object obj2)
        {
            bool areEqual = (obj1 == obj2);

            if (equals == areEqual)
            {
                return "\n\nSuccess!\n\n";
            }
            return "\n\nFailure!\n\n";
        }

If I call Assert(true, 2, 2), the output should be "Success!".
If I call Assert(false, 2, 2), the output should be "Failure!".

However, upon further inspection, (obj1 == obj2) returns false when I've passed the integer "2" for both obj1 and obj2. Does anyone know what I'm missing here?

Rufus L
  • 36,127
  • 5
  • 30
  • 43
Alex
  • 19
  • 5
  • 4
    You've boxed your integers, and you're now checking for referential equality, and two different boxes have two different references. – Jonathon Chase Jul 17 '19 at 16:47
  • You cannot compare the values of two `object` types with `==`. Use `.Equals()` and/or check if `IEquatable` is implemented first. – John Alexiou Jul 17 '19 at 17:25

2 Answers2

1

The reason you're getting this result is that you are boxing the integers to object type, and object types use the object reference to determine equality (and this would not happen for boxed objects) using the == operator.

One way to resolve this issue would be to make your method generic (which takes in any type), and then use the Equals method of the type itself (which for integers would be a comparison of the values). By making the method generic, you also remove the unnecessary boxing operation:

public static string Assert<T>(bool equals, T obj1, T obj2)
{
    bool areEqual = obj1.Equals(obj2);

    if (equals == areEqual)
    {
        return "\n\nSuccess!\n\n";
    }

    return "\n\nFailure!\n\n";
}

Now, there still may be some issues if T is a nullable type and obj1 is null, because we'll get a NullReferenceException if we try to call Equals on a null object.

To get around this, we might do a couple of things:

  1. Check for ReferenceEquals first, which will return true if both arguments are null. This will also short-circuit the need to call Equals if two references to the same object are passed in.
  2. Check if obj1 is not null before calling its Equals method

For example:

public static string Assert<T>(bool equals, T obj1, T obj2)
{
    bool areEqual = false;

    if (ReferenceEquals(obj1, obj2))
    {
        areEqual = true;
    }
    else if (obj1 != null)
    {
        areEqual = obj1.Equals(obj2);
    }

    if (equals == areEqual)
    {
        return "\n\nSuccess!\n\n";
    }

    return "\n\nFailure!\n\n";
}

Now if we want to, we can shorten the code using conditional || and && operators and the ?: ternary operator:

public static string Assert<T>(bool equals, T obj1, T obj2)
{
    bool areEqual = ReferenceEquals(obj1, obj2) || obj1 != null && obj1.Equals(obj2);

    return equals == areEqual
        ? "\n\nSuccess!\n\n"
        : "\n\nFailure!\n\n";
}
Rufus L
  • 36,127
  • 5
  • 30
  • 43
0

Use Equals and make sure to handle nulls

public static string Assert(bool equals, object obj1, object obj2)
{
    bool areEqual = obj1 == null && obj2 == null || obj1 != null && obj1.Equals(obj2);
    return equals == areEqual
        ? "\n\nSuccess!\n\n"
        : "\n\nFailure!\n\n";
}

Equals will be the overridden version of the runtime type of the objects, not the static type.

Note that the == operator might be overridden (e.g. in string). But the static type is used at compile-time to determine which version will be used. But for the Equals method, the run-time type will be used. Let's make a test

string s = "hallo";
string a = "hal";
string b = "lo";

// Constructed, so that we will get the same string value as `s`, but a different reference.
string t = a + b;

object o1 = s;
object o2 = t;
Console.WriteLine(s == t);   // ==> True
Console.WriteLine(o1 == o2); // ==> False
Console.WriteLine(s.Equals(t));   // ==> True
Console.WriteLine(o1.Equals(o2)); // ==> True
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188