简体   繁体   中英

Why is this not working? (Generic Equals Helper)

SOLVED! This works, I need to tell the compiler that T implements IEquatable of course...

public static bool secureEquals<T>(T obj1, object obj2)
    where T: class, IEquatable<T>
{...

public static bool secureEquals<T>(T obj1, T obj2)
    where T: class, IEquatable<T>
{....

Question:

I tried to put repeated functionality of IEquatable implementations and Equals overrides into a separate static class like so:

public static class EqualsHelper
{
    public static bool secureEquals<T>(T obj1, object obj2)
       where T : class
    {
        if (obj2 is T)
        {
            return secureEquals(obj1, obj2 as T);
        }
        else
        {
            return false;
        }
    }

    public static bool secureEquals<T>(T obj1, T obj2)
    {
        if (obj1 == null)
        {
            if (obj2 != null)
                return false;
        }
        else
        {
            if (!obj1.Equals(obj2)) //this calls Dummy.Equals(object other)!
                return false;
        }

        return true;
    }


    public static bool secureEquals(double[] obj1, double[] obj2)
    {
        if (obj1.Length != obj2.Length)
            return false;

        for (int i = 0; i < obj1.Length; ++i)
        {
            if (obj1[i] != obj2[i])//ok for doubles if they are generated in the same way? I guess so!
                return false;
        }

        return true;
    }

public class Dummy : IEquatable<Dummy>
{
    public Dummy(string member)
    {
        _member = member;
    }

    private string _member;


    public virtual bool Equals(Dummy other)
    {
        return this._member == other._member;
    }

    public override bool Equals(object other)
    {
        return EqualsHelper.secureEquals(this, other);
    }

}

    static void Main(string[] args)
    {
        Dummy d1 = new Dummy("Hugo");
        Dummy d2 = new Dummy("Hugo");

        object d2obj = (object)d2;

        bool ret = d1.Equals(d2obj);
    }

The idea was: d1.Equals(d2obj) calls Dummy.Equals(object) calls EqualsHelper.secureEquals(T, obj) calls EqualsHelper.secureEquals(T, T) calls Dummy.Equals(Dummy).

The last call however calls Dummy.Equals(object), even though everything is typed to T there.

What am I missing?

PS: I know that replacing the call with:

            if (!((IEquatable<T>)obj1).Equals(obj2)) //this calls Dummy.Equals(object other)!

does the trick, but why is it not working otherwise?

Why: because method invoke here is static typed, and the only available Equals involving a T with no generic constraint is object.Equals(object) . The exact same IL has to be able to handle every T - C# generics are not like C++ templates; no per-T overload resolution occurs.

As an aside: you might also want to look at EqualityComparer<T>.Default.Equals(obj1,obj2) , which will handle IEquatable<T> , Nullable<T> , etc automatically:

public static bool secureEquals<T>(T obj1, object obj2) where T : class
{
    return EqualityComparer<T>.Default.Equals(obj1, obj2 as T);
}

The Equals overload within EqualsHelper.secureEquals is resolved when EqualsHelper is compiled - and that code doesn't know whether T implements IComparable<T> or not, so all that's left is Equals(Object) . You can add a constraint to T which would make it use the right overload:

public static bool SecureEquals<T>(T obj1, T obj2) where T : IEquatable<T>

Of course, this would limit the classes with which you could use it.

(As an aside, note that I've renamed secureEquals to SecureEquals to comply with .NET naming conventions. I'd also not use the word "secure" here at all personally - there's nothing security-sensitive here.)

Because in your secureEquals you have no constraints, and compiler always assumes Object.Equals exist. Add interface constraint for your T.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM