Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does KeyValuePair not override Equals() and GetHashCode()?

I was going to use KeyValuePair in a comparison-intensive code and was perplexed checking how it is implemented in .NET (s. below)

Why does it not override Equals and GetHashCode for efficiency (and not implement ==) but instead uses the slow reflection-based default implementation?

I know that structs/value types have a default implementation based on reflection for their GetHashCode() and Equals(object) methods, but I suppose it is very inefficient compared to overriding equality if you do a lot of comparisons.


EDIT I made some tests and found out that in my scenario (WPF Lists) both default KeyValuePair and my own implementation of a struct overriding GetHashCode() and Equals(object) are both much more slow then an implementation as a class!


http://referencesource.microsoft.com/#mscorlib/system/collections/generic/keyvaluepair.cs,8585965bb176a426

// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** Interface:  KeyValuePair
** 
** <OWNER>[....]</OWNER>
**
**
** Purpose: Generic key-value pair for dictionary enumerators.
**
** 
===========================================================*/
namespace System.Collections.Generic {

    using System;
    using System.Text;

    // A KeyValuePair holds a key and a value from a dictionary.
    // It is used by the IEnumerable<T> implementation for both IDictionary<TKey, TValue>
    // and IReadOnlyDictionary<TKey, TValue>.
    [Serializable]
    public struct KeyValuePair<TKey, TValue> {
        private TKey key;
        private TValue value;

        public KeyValuePair(TKey key, TValue value) {
            this.key = key;
            this.value = value;
        }

        public TKey Key {
            get { return key; }
        }

        public TValue Value {
            get { return value; }
        }

        public override string ToString() {
            StringBuilder s = StringBuilderCache.Acquire();
            s.Append('[');
            if( Key != null) {
                s.Append(Key.ToString());
            }
            s.Append(", ");
            if( Value != null) {
               s.Append(Value.ToString());
            }
            s.Append(']');
            return StringBuilderCache.GetStringAndRelease(s);
        }
    }
}
like image 362
Mikhail Poda Avatar asked Jul 07 '16 16:07

Mikhail Poda


2 Answers

As the other answers point out, you get equality and hashing "for free", so you don't need to override them. However, you get what you pay for; the default implementations of equality and hashing are (1) not particularly efficient in some cases, and (2) may do bitwise comparisons, and hence can do things like compare negative zero and positive zero doubles as different when logically they are equal.

If you expect that your struct will frequently be used in contexts that require equality and hashing, then you should write custom implementations of both and follow the appropriate rules and guidelines.

https://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/

So, to answer your question: why did no one do so for a particular type? Likely because they did not believe that doing so was a good use of their time compared to all the other things they had to do to improve the base class libraries. Most people do not compare key-value pairs for equality, so optimizing it was probably not a high priority.

This is of course conjectural; if you actually want to know the reason why something did not get done on a particular day, you're going to have to track down all the people who did not do that action and ask them what else they were doing that was more important on that day.

like image 179
Eric Lippert Avatar answered Oct 16 '22 04:10

Eric Lippert


It is a struct, Structs inherit from ValueType and that type already overrides the implementation of Equals and GetHashCode.

It does not support ==, doing the following won't even compile

var result = new KeyValuePair<string, string>("KVP", "Test1") ==
         new KeyValuePair<string, string>("KVP", "Test2");

You will receive the error "Operator '==' cannot be applied to operands of type KeyValuePair<string, string> and KeyValuePair<string, string>"

like image 34
Scott Chamberlain Avatar answered Oct 16 '22 06:10

Scott Chamberlain