Why does ((object)(int)1).Equals(((object)(ushort)1)) yield false?
Asked Answered
R

3

12

I have the Situation that I have an object which I want to check for equality with another object.

public static bool Equals(object a, object b)
{
    return a.Equals(b);
}

A Problem occurs when a = 1 (integer) and b = 1 (ushort (or basically not integer)). I wondered whether this shouldn't yield true, but it does return false...

Edit

What makes it even worse is this:

Hashtable ht = new Hashtable();
ht.Add((int)1, "SOME STRING");
ht.Add((short)1, "SOME STRING");
ht.Add((long)1, "SOME STRING");

I think that the value '1' should only be allowed once.

Recognizee answered 14/8, 2014 at 10:6 Comment(8)
an integer is not an unsigned short ushort. This should be the reasonCortex
It's rarely a good idea for x.Equals(y) to be true, but x.GetType() == y.GetType() to be false.Heaveho
@JonSkeet is it ever? do you have an example of it being a good idea?Mouseear
@weston: I can't think of any examples off-hand, but I don't like being completely blanket :)Heaveho
@JonSkeet I figured it was a polite way of saying that it's never a good idea :)Quirinus
@Quirinus Well yes that is my view on it, but I'd genuinely love to hear of an example, and it sounded like Jon might have come across this in the wild. I know it's possible to have a correct equals method between two classes wrt transitivity and symmetry, but I don't know why or how that situation could arise.Mouseear
@Mouseear Consider a Square s with a side of 4 and a 4x4 Rectangle r. Its reasonable (though it would depend on the case) for s.equals(r) to be true, but for s.GetType() == y.GetType() to be false.Ulceration
@Dgrin91 I accept that's possible, but I think to say it's reasonable depends on the application and the reasons why you needed a separate square class in the first place. But the main reason against doing that is that it's hard to maintain the rules of reflexivity and transitivity when working with multiple classes assuming those classes have the same aspects (width and height in this case). And it is impossible when they have different aspects.Mouseear
C
19

Int32.Equals(object) returns true only if the other object is also an instance of Int32:

true if obj is an instance of Int32 and equals the value of this instance; otherwise, false.

In code (ILSpy, .NET 4):

public override bool Equals(object obj)
{
    return obj is int && this == (int)obj;
}

Since obj is int returns false you get a false.

Edit: ragarding to your edit(Hashtable with "similar" keys): if you don't want to allow duplicate objects use a Dictionary<int, string> instead(preferred) or add only ints to the HashTable.

Clemons answered 14/8, 2014 at 10:10 Comment(2)
@TimSchmelter you didnt :)Cortex
Microsoft provides the actual implementation, no decompilation required!Sylph
M
3

Here's a simple class and implementation of equality comparers. As you can see, the standard apporach for equals is to make sure they are of the same time first, and then, that the inside matches (in our case, a string and a date).

If you want something else, you can always override it to your heart content, and cast both sides to something you're happy with :)

public struct InputEntry
{
    public DateTime Date { get; set; }
    public string Entry { get; set; }

    public bool Equals(InputEntry other)
    {
        return Date.Equals(other.Date) && string.Equals(Entry, other.Entry);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        return obj is InputEntry && Equals((InputEntry) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return ( Date.GetHashCode()*397) 
                   ^ (Entry != null ? Entry.GetHashCode() 
                                    : 0);
        }
    }

    public static bool operator ==(InputEntry left, InputEntry right)
    {
        return left.Equals(right);
    }

    public static bool operator !=(InputEntry left, InputEntry right)
    {
        return !left.Equals(right);
    }

    private sealed class EntryDateEqualityComparer 
                                    : IEqualityComparer<InputEntry>
    {
        public bool Equals(InputEntry x, InputEntry y)
        {
            return string.Equals(x.Entry, y.Entry) && x.Date.Equals(y.Date);
        }

        public int GetHashCode(InputEntry obj)
        {
            unchecked
            {
                return ( (obj.Entry != null ? obj.Entry.GetHashCode() : 0)*397) 
                       ^ obj.Date.GetHashCode();
            }
        }
    }

    private static readonly IEqualityComparer<InputEntry> 
                  EntryDateComparerInstance = new EntryDateEqualityComparer();

    public static IEqualityComparer<InputEntry> EntryDateComparer
    {
        get { return EntryDateComparerInstance; }
    }
}
Mccaskill answered 14/8, 2014 at 10:15 Comment(0)
C
2

Because they do not have the same type. You can try to cast them both to int, and then compare the ints, if the cast is successful.

public static bool Equals(object a, object b)
{
     try
     {
         return ((int)a).equals((int)b);
     }
     catch
     {
         return a.Equals(b);
     }
}
Carbrey answered 14/8, 2014 at 10:11 Comment(9)
this is not usefull. Users of this method cannot see that inside the method the object is casted to int ... also a try {} only i have never seen. Only try {} finally {} or try{} catch {} [finally{}]Cortex
Fair enough, I added the catch, but he seems to want to compare types that can be cast to an int, so this would solve his problems. Why would they need to see that inside the method the object is casted?Carbrey
Cause Equals is a common method of object and no one will expect your behaviorCortex
He asks why it is so, I tell him, and tell him how he can make it different, doesn't merrit the -1 in my opinion (obviously) :-)Carbrey
you didnt tell him why, because this is not the equals of object, it is your custom equals which doesnt explain the reason why it failes in his Scenario. But i will remove the -1 cause your code is running right now.Cortex
just my Point of view :) your solution is not usefull like you did itCortex
His question was why his own custom equals function did not work like he thought it should...Carbrey
yes but he has no custom implementation. as you can see it is the Equals of object that he useCortex
no just a call to object.Equals() ... anyway :) lets say we are both rightCortex

© 2022 - 2024 — McMap. All rights reserved.