Оператор '==' не может быть применен к типу T? - PullRequest
12 голосов
/ 27 апреля 2011

Я думал, что этот метод действителен, но я ошибался:

static void Equals<T>(T x, T y)
{
    return x == y;    //operator == can't be applied to type T
}

После прочтения спецификации (§7.2.4 в v3.0 и §7.3.4 в v4.0):

7.2.4 Разрешение перегрузки двоичного оператора

Операция вида x op y, где op - это перегружаемый двоичный оператор, x - это выражение типа X, а y - это выражениетип Y обрабатывается следующим образом:

  • Определяется набор пользовательских операторов-кандидатов, предоставляемых X и Y для оператора операции op (x, y).Набор состоит из объединения операторов-кандидатов, предоставленных X, и операторов-кандидатов, предоставленных Y, каждый из которых определяется по правилам §7.2.5.Если X и Y относятся к одному и тому же типу или если X и Y получены из общего базового типа, то операторы-кандидаты совместно используются в объединенном наборе только один раз.

  • Если наборПользовательские операторы-кандидаты не пустые, тогда они становятся набором операторов-кандидатов для операции.В противном случае предопределенные реализации бинарных операторов, включая их поднятые формы, становятся набором операторов-кандидатов для операции.Предопределенные реализации данного оператора указаны в описании оператора (с §7.7 по §7.11).

  • Правила разрешения перегрузки согласно §7.4.3 применяются к наборуоператоры-кандидаты выбирают лучший оператор относительно списка аргументов (x, y), и этот оператор становится результатом процесса разрешения перегрузки.Если при разрешении перегрузки не удается выбрать один лучший оператор, возникает ошибка времени компиляции.

На шаге 2 я думаю, что должна применяться эта предопределенная реализация:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

, поскольку все в C # происходит от Object.Как может произойти ошибка времени компиляции на шаге 3?Я не думаю, что это возможно, что «разрешение перегрузки не удается выбрать» в этом случае.

РЕДАКТИРОВАТЬ Вопрос пришёл мне в голову, когда я реализовывал нечто подобное:

class EnumComparer<TEnum> : IEqualityComparer<TEnum>
{
    public bool Equals(TEnum x, TEnum y)
    {
        return x == y;
    }
    public int GetHashCode(TEnum obj)
    {
        return (int)obj;
    }
}

Боюсь, мне нужно построить выражение и динамически вызывать его в методе Equals.

Ответы [ 4 ]

20 голосов
/ 27 апреля 2011

Хорошо для чтения спецификации, но вы перестали читать слишком рано.Если бы вы читали дальше, вы бы получили этот бит:


Для предопределенных операторов равенства ссылочного типа требуется один из следующих параметров:

  • Оба операндаявляются значением типа, известного как ссылочный тип или литерал null.Кроме того, существует явное ссылочное преобразование из типа любого операнда в тип другого операнда.

  • Один операнд является значением типа T, где T является параметром типа, а другой операнд является литералом null.Кроме того, T не имеет ограничения типа значения.

Если не выполняется одно из этих условий, возникает ошибка времени привязки.(*)


Ошибка не в разрешении перегрузки;ошибка в том, что при разрешении перегрузки был бы выбран предопределенный оператор равенства ссылочных типов, а у вас нет ссылочных типов.

Рассмотрим ваш код.Что мешает T быть типом значения без определенного оператора равенства?Ничего такого.Предположим, мы вернулись к версии объекта;оба операнда будут располагаться в разных местах и, следовательно, будут неравнозначными, даже если они имеют одинаковое содержание.Поскольку это медленно, сбивает с толку и неправильно, даже пытаться нелегально.

Почему вы пытаетесь сделать это в первую очередь?Если ваш метод работает, а это не так, тогда ваш метод будет на хуже , чем просто использование == в первую очередь.Какое значение вы намереваетесь добавить в мир с помощью этого метода?


(*) Я сообщил о грамматической ошибке в этом предложении сопровождающим спецификаций.

7 голосов
/ 27 апреля 2011

Это могло бы сработать, если бы оно знало, что where T : class, делая эталонное сравнение.Операторы, как правило, имеют очень небольшую поддержку обобщений, но есть обходные пути.MiscUtil предлагает косвенную поддержку для операторов на дженериках, в противном случае EqualityComparer<T>.Default.Equals(x,y) - хороший выбор.

1 голос
/ 27 апреля 2011

Мне нравится использовать EqualityComparer<T>.Default для этого.

Он основан на переопределенном методе Equals, но использует IEquatable<T>, когда доступен, избегая упаковок для типов значений, реализующих его.

EqualityComparer<T>.Default.Equals(x, y)
0 голосов
/ 27 апреля 2011

используйте .Equals() метод и убедитесь, что T орудие IComparable

...