在.Net 2.5中,我通常可以在值和类型默认值
之间得到相等比较(==)if (myString == default(string))
但是当我尝试在默认的KeyValuePair和KeyValuePair上运行相等比较时,我得到以下异常
代码示例(来自预扩展方法,proto-lambda静态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&LT;串,对象&gt;' 和 'System.Collections.Generic.KeyValuePair&LT;串,对象&gt;'
是否因为作为结构,KeyValuePair不可为空?如果是这种情况,为什么,实际上,默认是为了处理不可为空的类型?
编辑
为了记录,我选择@Chris Hannon作为选择的答案,因为他给了我正在寻找的东西,最优雅的选择,以及简洁的解释,但我鼓励阅读@Dasuraga以获得非常全面的解释。为什么会这样呢
答案 0 :(得分:55)
这是因为KeyValuePair<TKey, TValue>
没有定义自定义==运算符,并且未包含在可以使用它的预定义值类型列表中。
以下是该运营商MSDN documentation的链接。
对于预定义的值类型,如果操作数的值相等,则相等运算符(==)返回true,否则返回false。
在这种情况下,您最好选择等同性检查,因为这不是您可以控制的结构,而是调用default(KeyValuePair<TKey,TValue>).Equals(pair)
。
答案 1 :(得分:5)
(如果您不关心与此错误相关的泛型讨论,您可以跳到最后寻找“真实”答案)
正如错误所说,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是“相同的”(在值中,不是同一个对象)。
所以这个函数需要两个KVP(k,v)和(k',v')并且当且仅当k == k'和v == v'时才会返回true(直观意义上)。< / p>
但这有必要吗?看来你遇到问题的测试是基于对FirstOrDefault返回的某种验证。
但是你的函数叫FirstOrDefault:
是有原因的返回的第一个元素 满足条件或的条件 如果没有此类元素,则为默认值 找到。强>
(强调我的)
如果找不到某些内容,会返回默认值,这意味着如果您的谓词未经过验证,您将获得等于(默认值(TKey),默认值(TValue)的KeyValuePair。< / p>
您的代码因此(打算)检查pair.Key == default(TKey),仅检测返回默认值(TKey)。返回pair.Key从一开始就不会更有意义吗?
答案 2 :(得分:4)
为了在任何类或结构上使用“==”相等运算符,它需要覆盖运算符: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
编辑:正如Eric Lippert在评论中纠正我一样,类显然不需要覆盖等于运算符“==”才有效。它会编译好并进行引用相等性检查。我的错误。
答案 3 :(得分:3)
失败的原因与以下相同:
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。
快乐的编码。
答案 4 :(得分:1)
默认值是标量类型。
问自己这个问题:KVP的意味着什么具有默认值?
对于非标量,默认值是调用nil构造函数得到的任何值。假设KVP Equals执行实例身份比较,我希望它返回false,因为每次调用构造函数时都会得到一个新对象。
答案 5 :(得分:1)
这方向略有不同,但我假设你查询了一个字典来获得这个结果,然后你想检查它是否返回了有效的结果。
我发现更好的方法是查询实际值而不是整个KeyValuePair,如下所示:
var valitem = MyDict.Values.FirstOrDefault(x =&gt; x.Something == aVar);
现在您可以检查valitem是否为null。同样,它并没有直接回答您的问题,但提供了可能是您预期目标的替代方法。