Почему я не могу сравнить KeyValuePair <TKey, TValue> со значением по умолчанию
В .Net 2.5 Обычно я могу получить сравнение равенства (==) между значением и его типом по умолчанию
if (myString == default(string))
Однако я получаю следующее исключение, когда пытаюсь выполнить сравнение равенства по умолчанию KeyValuePair и KeyValuePair
Пример кода (из метода предварительной расшифровки, прото-лямбатический статический класс ListUtilities:))
public static TKey
FirstKeyOrDefault<TKey, TValue>(Dictionary<TKey, TValue> lookups,
Predicate<KeyValuePair<TKey, TValue>> predicate)
{
KeyValuePair<TKey, TValue> pair = FirstOrDefault(lookups, predicate);
return pair == default(KeyValuePair<TKey, TValue>) ?
default(TKey) : pair.Key;
}
Исключение:
Оператор '==' не может применяться к операнды типа 'System.Collections.Generic.KeyValuePair < строка, объект > ' а также 'System.Collections.Generic.KeyValuePair < строка, объект > '
Это потому, что в качестве структуры KeyValuePair не имеет значения NULL? Если это так, почему, как, предположительно, по умолчанию было реализовано обращение к типам с нулевым значением?
EDIT
Для записи я выбрал @Chris Hannon в качестве выбранного ответа, поскольку он дал мне то, что я искал, самый элегантный вариант и краткое объяснение, однако я поощряю чтение @Dasuraga для очень подробного объяснения относительно почему это так.
Ответы
Ответ 1
Это происходит потому, что KeyValuePair<TKey, TValue>
не определяет пользовательский == оператор и не входит в предопределенный список типов значений, которые могут его использовать.
Вот ссылка на документацию MSDN для этого оператора.
Для предопределенных типов значений оператор равенства (==) возвращает true, если значения его операндов равны, в противном случае - false.
Ваш лучший выбор для проверки равенства в этом случае, потому что это не структура, над которой вы контролируете, заключается в вызове default(KeyValuePair<TKey,TValue>).Equals(pair)
.
Ответ 2
(Если вам неинтересно обсуждение обобщений, связанных с этой ошибкой, вы можете просто перейти к концу для своего "реального" ответа)
Как говорит ошибка, нет теста на равенство для KeyValuePairs (т.е. нет встроенного метода сравнения). Причина этого заключается в том, чтобы избежать необходимости устанавливать ограничения на типы KeyValuePairs (есть много случаев, когда ключевые значения сравнения никогда не будут выполняться).
Очевидно, что если вы хотите сравнить KeyValuePairs, я бы предположил, что вы хотите проверить, являются ли ключи и значения равными. Но это подразумевает целый беспорядок вещей, в частности, что TKey и TValue являются сопоставимыми типами (т.е. они реализуют интерфейс IComparable)
Вы можете написать свою собственную функцию сравнения между keyvaluepairs, например:
static bool KeyValueEqual<TKey , TValue>(KeyValuePair<TKey, TValue> fst,
KeyValuePair<TKey, TValue> snd)
where TValue:IComparable
where TKey:IComparable
{
return (fst.Value.CompareTo(snd.Value)==0)
&& (snd.Key.CompareTo(fst.Key)==0);
}
(Простите ужасный отступ)
Здесь мы указываем, что TKey и TValue сопоставимы (через функцию-член CompareTo).
Функция CompareTo (как определено для предопределенных типов) возвращает 0, когда два объекта равны, à la strcmp. a.ComparesTo(b) == 0 означает, что a и b являются "одинаковыми" (по значению, а не одному и тому же объекту).
поэтому эта функция возьмет два KVPs (k, v) и (k ', v') и вернет true тогда и только тогда, когда k == k 'и v == v' (в интуитивном смысле).
Но нужно ли это? Кажется, ваш тест, в котором у вас возникли проблемы, основан на некоторой проверке при возврате FirstOrDefault.
Но есть причина, по которой ваша функция называется FirstOrDefault:
Возвращает первый элемент последовательность, удовлетворяющая условию или значение по умолчанию, если нет такого элемента найдено.
(акцент мой)
Эта функция возвращает значения по умолчанию, если что-то не найдено, что означает, что если ваш предикат не проверен, вы получите ключ KeyValuePair, равный (по умолчанию (TKey), по умолчанию (TValue).
Таким образом, ваш код (намеревается) проверяет, поддерживает ли пара .Key == default (TKey) только возврат по умолчанию (TKey). Разве это не имело бы больше смысла возвращать пару.Кей с самого начала?
Ответ 3
Чтобы использовать оператор равенства "==" для любого класса или структуры, он должен переопределить оператор: http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
KeyValuePair этого не делает, и поэтому вы получаете ошибку компиляции. Обратите внимание: вы получите ту же ошибку, если просто попробуете это:
var k1 = new KeyValuePair<int,string>();
var k2 = new KeyValuePair<int,string>();
bool b = k1 == k2; //compile error
РЕДАКТИРОВАТЬ:. Как писал Эрик Липперт в комментариях, для классов явно не нужно переопределять оператор равенства для "==". Он будет компилироваться и выполнять контрольную проверку равенства. Моя ошибка.
Ответ 4
Он не работает по той же причине, что и:
var kvp = new KeyValuePair<string,string>("a","b");
var res = kvp == kvp;
Разумеется, ключ находится в сообщении об ошибке. (Это не имеет никакого отношения к default
).
Operator '==' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<string,string>' and 'System.Collections.Generic.KeyValuePair<string,string>'
Оператор ==
не определен для KeyValuePair<T,U>
.
Сообщения об ошибках FTW.
Счастливое кодирование.
Ответ 5
По умолчанию задаются скалярные типы.
Задайте себе этот вопрос: что значит для KVP иметь значение по умолчанию?
Для нескаляров по умолчанию используется то, что вы получаете от вызова конструктора nil. Предполагая, что KVP Equals выполняет сравнение идентичности экземпляра, я ожидаю, что он вернет false, поскольку вы получаете новый объект каждый раз при вызове конструктора.
Ответ 6
Это немного в другом направлении, но я предполагаю, что вы запросили словарь для получения этого результата, а затем хотите проверить, вернул ли он верный результат или нет.
Я нашел, что лучший способ сделать это - запросить фактическое значение вместо всего KeyValuePair, например:
var valitem = MyDict.Values.FirstOrDefault(x = > x.Something == aVar);
Теперь вы можете проверить, является ли valitem нулевым или нет. Опять же, он напрямую не отвечает на ваш вопрос, но предлагает, какой может быть альтернативный подход к вашей намеченной цели.