Оператор '==' не может применяться к типу T?

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

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 в версии 4.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);

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

EDIT Вопрос пришел мне на ум, когда я реализовал что-то вроде этого:

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

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

Ответ 1

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


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

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

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

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


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

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

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


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

Ответ 2

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

Ответ 3

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

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

EqualityComparer<T>.Default.Equals(x, y)

Ответ 4

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