为什么我不能比较KeyValuePair <tkey,tvalue =“”>默认</tkey,>

时间:2011-06-16 23:47:37

标签: c# .net key-value

在.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以获得非常全面的解释。为什么会这样呢

6 个答案:

答案 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。同样,它并没有直接回答您的问题,但提供了可能是您预期目标的替代方法。