Оператор '==' не может применяться к типу 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