Почему это не работает? (Общий Равный Помощник) - PullRequest
3 голосов
/ 03 января 2012

РЕШИТЬ! Это работает, я должен сказать компилятору, что T, конечно, реализует IEquatable ...

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>
{....

Вопрос:

Я пытался поместить повторяющуюся функциональность реализаций IEquatable и переопределений Equals в отдельный статический класс, например:

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);
    }

Идея была: d1.Equals (d2obj) вызывает Dummy.Equals (объект) вызывает EqualsHelper.secureEquals (T, obj) вызывает EqualsHelper.secureEquals (T, T) вызывает Dummy.Equals (Dummy).

Последний вызов, однако, вызывает Dummy.Equals (объект), даже если там все напечатано в T.

Чего мне не хватает?

PS: я знаю, что замена вызова на:

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

делает трюк, но почему не работает иначе?

Ответы [ 3 ]

5 голосов
/ 03 января 2012

Почему: потому что метод вызова здесь имеет статическую типизацию, и единственное доступное Equals, включающее T без общего ограничения, - object.Equals(object). Точно такой же IL должен быть в состоянии обрабатывать каждый T - Обобщения C # не похожи на шаблоны C ++; разрешение перегрузки на T не возникает.

В качестве отступления: вы также можете посмотреть на EqualityComparer<T>.Default.Equals(obj1,obj2), который будет обрабатывать IEquatable<T>, Nullable<T> и т. Д. Автоматически:

public static bool secureEquals<T>(T obj1, object obj2) where T : class
{
    return EqualityComparer<T>.Default.Equals(obj1, obj2 as T);
}
4 голосов
/ 03 января 2012

Перегрузка Equals в EqualsHelper.secureEquals разрешается при компиляции EqualsHelper, и этот код не знает, реализует ли T IComparable<T> или нет, поэтому остается только Equals(Object). Вы можете добавить ограничение к T, которое заставит его использовать правильную перегрузку:

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

Конечно, это ограничит классы, с которыми вы можете его использовать.

(Кроме того, обратите внимание, что я переименовал secureEquals в SecureEquals, чтобы соответствовать соглашениям о присвоении имен .NET. Я бы также не использовал здесь слово «безопасный» лично - нет ничего чувствительного к безопасности. здесь.)

0 голосов
/ 03 января 2012

Поскольку в вашем secureEquals нет никаких ограничений, и компилятор всегда предполагает, что Object.Equals существуют. Добавьте ограничение интерфейса для вашего T.

...