Why can't I compare a KeyValuePair<TKey, TValue> with default
In .Net 2.5 I can usually get an equality comparison (==) between a value and its type default
if (myString == default(string))
However I get the following exception when I try to run an equality comparison on a default KeyValuePair and a KeyValuePair
Code Sample (from a pre-extension method, proto-lambda static ListUtilities class :) )
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;
}
Exception:
Operator '==' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<string,object>' and 'System.Collections.Generic.KeyValuePair<string,object>'
Is it because, as a struct, the KeyValuePair is not nullable? If this is the case, why, as, presumably, default was implemented to handle not nullable types?
EDIT
For the record, I chose @Chris Hannon as selected answer, as he gave me what I was looking for, the most elegant option, and a succinct explanation, however I do encourage reading @Dasuraga for a very comprehensive explanation as to why this is the case
This happens because KeyValuePair<TKey, TValue>
does not define a custom == operator and is not included in the predefined list of value types that can use it.
Here is a link to the MSDN documentation for that operator.
For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise.
Your best bet for an equality check in this case, because this is not a struct you have control over, is to call default(KeyValuePair<TKey,TValue>).Equals(pair)
instead.
(If you don't care about the generics discussion linked to this error, you can just jump to the end for your "real" answer)
As the error says, there is no equality testing for KeyValuePairs (ie there is no built-in comparison method). The reason for this is to avoid having to place constraints on the types of KeyValuePairs (there are many cases where key,value comparisons would never be made).
Obviously if you want to compare thes KeyValuePairs, I'd imagine what you'd want is to check if the keys and values are equal. But this implies a whole mess of things , notably that TKey and TValue are both comparable types (ie they implement the IComparable interface)
You could write your own comparison function between keyvaluepairs, for example:
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);
}
(Excuse the awful indentation)
Here we impose that TKey and TValue are both comparable (via the CompareTo member function).
The CompareTo function (as defined for pre-defined types) returns 0 when two objects are equal , à la strcmp . a.ComparesTo(b)==0 means a and b are the "same"(in value, not the same object).
so this function would take two KVPs (k,v) and (k',v') and would return true if and only if k==k' and v==v' (in the intuitive sense).
But is this necessary? It seems your test where you're having problems is based on some sort of verification on the return of FirstOrDefault.
But there's a reason your function's called FirstOrDefault:
Returns the first element of the sequence that satisfies a condition or a default value if no such element is found.
(emphasis mine)
This function returns default values if something isn't found , meaning if your predicate isn't verified you'll get a KeyValuePair equal to (default(TKey),default(TValue).
Your code therefore (intends to) check whether pair.Key==default(TKey), only to return default(TKey) anyways . Wouldn't it just make more sense to return pair.Key from the outset?
In order you to use the "==" equality operator on any class or struct, it needs to override the operator: http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
KeyValuePair doesn't, and therefore you get the compile error. Note, you'll get the same error if you just try this:
var k1 = new KeyValuePair<int,string>();
var k2 = new KeyValuePair<int,string>();
bool b = k1 == k2; //compile error
EDIT: As Eric Lippert corrected me in the comments, classes obviously don't need to override the equality operator for "==" to be valid. It'll compile fine and do a reference equality check. My mistake.
链接地址: http://www.djcxy.com/p/58614.html上一篇: 在泛型函数中使用重载运算符==