Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

equals() and == in a generic function

Tags:

c#

equals

I am making a comparer for set operation on various types.

So I have a generic class

 public class Comparer<T, Tid>
...
     public bool Equals(T x, T y)
       {
          var xid = m_idfunc(x);
           var yid = m_idfunc(y);
           return (Tid)xid == (Tid)yid;
       }

Where m_idfunc is a lambda passed in to the Comparer constructor, it is

Func<T,Tid>

I create a comparer with Tid = string. I get in the equals function xid = string1, yid = string2

If string1 and string 2 are the same ("foo" and "foo" say)

xid == yid

yields false

(Tid)xid == (Tid)yid

also yields false (it should not be necessary - I was just getting desperate)

heres my immediate window - paused on the return xid == yid line

yid.GetType() == typeof(string)
true
xid.GetType() == typeof(string)
true
xid==yid
false
(string)xid==(string)yid
true
xid.Equals(yid)
true

Whats going on?

like image 581
pm100 Avatar asked Oct 07 '22 16:10

pm100


1 Answers

What’s interesting about this is that it might just work the way you want it to. Here’s an example:

using System;
using System.Text;

namespace ConsoleApplication1 {

    class Program {

        public static void Main()  {
            string myString = "1";
            object objectString = "1";
            string myCopiedString = string.Copy(myString);
            string internedString = string.Intern(myCopiedString);

            Console.WriteLine(myString); //1
            Console.WriteLine(objectString); //1
            Console.WriteLine(myCopiedString); //1
            Console.WriteLine(internedString); //1

            Console.Write(objectString == myString); //true
            Console.Write(objectString == "1"); //true
            Console.Write(objectString == myCopiedString); //!!!FALSE!!!!
            Console.Write(objectString == internedString); //true
            Console.Write(objectString == SomeMethod()); //!!!FALSE!!!
            Console.Write(objectString == SomeOtherMethod()); //true
        }

        public static string SomeMethod() {
            StringBuilder sb = new StringBuilder();
            return sb.Append("1").ToString();
        }

        public static string SomeOtherMethod() {
            return "1".ToString();
        }        
    }
}

The reason why it might work is due to string interning. So, this is definitely one to watch out for, because it can actually work when you test it, but depending on the implementation, it might suddenly break.

In your case, you need to determine whether you care about Reference equality or "value" equality. == is reference equality, which again, depending on whether or not the string is interned may be true. I suspect you actually want to use EqualityComparer<T>.Default.Equals in your function.

If you run open this in VS you'll see the compiler warning: “Possible unintended reference comparison; to get a value comparison, cast the left hand side to type 'string'”. In your case however, the compiler can't warn you, because as far as it knows, the types are objects, it doesn't know that one or both are string.

like image 51
aquinas Avatar answered Oct 10 '22 04:10

aquinas