Search code examples
c#unity-game-engineoperator-overloadingoverridingiequatable

C# - Can't override ==


I have the following class (built for Unity Game Engine)

using System;
using System.Collections.Generic;
using UnityEngine;

public class Biome : ScriptableObject, IEquatable<Biome>
{
    // ...

    //
    // IEquatable
    //

    public bool Equals(Biome other)
    {
        if (other == null)
            return false;

        return this.name == other.name;
    }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;

        Biome other = obj as Biome;

        if (other == null) return false;

        return Equals(other);
    }

    public override int GetHashCode()
    {
        return this.name.GetHashCode();
    }

    public static bool operator ==(Biome biome1, Biome biome2)
    {
        if (object.ReferenceEquals(biome1, biome2)) return true;
        if (object.ReferenceEquals(null, biome1)) return false;
        if (object.ReferenceEquals(null, biome2)) return false;

        return biome1.Equals(biome2);
    }

    public static bool operator !=(Biome biome1, Biome biome2)
    {
        if (object.ReferenceEquals(biome1, biome2)) return false;
        if (object.ReferenceEquals(biome1, null)) return true;
        if (object.ReferenceEquals(biome2, null)) return true;

        return !biome1.Equals(biome2);
    }
}

When I try to do test, the function Equals seems to be working, but the operator == gives me a different result.

    [Test]
    public void FooTest()
    {
        ScriptableObject biome1 = ScriptableObject.CreateInstance("Biome");
        ScriptableObject biome2 = ScriptableObject.CreateInstance("Biome");

        biome1.name = "Biome #1";
        biome2.name = "Biome #1";

        Assert.IsTrue(biome1.Equals(biome2));
        Assert.IsTrue(biome1 == biome2);  // This one fails

    }

Am I doing something wrong with my implementation?

UPDATE: Here is the full class, in case it makes a difference: https://www.hastebin.com/divazubero.cpp


Solution

  • The problem is that your variables are of type ScriptableObject, not of type Biome.

    The compiler has to decide at compile-time which overload to call. And since it does not know at compile-time that the run-time type will be Biome, it emmits a call to the == operator of ScriptableObject.
    If that class doesn't have a overridden == operator, the operator of object is called (which does a simple ReferenceEquals which is of course false).

    == operator overloading is not virtual.

    If you use the specific type Biome in your test, it will work as expected.