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

北慕城南 提交于 2020-01-13 08:58:07

问题


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);
        }
    }
}

回答1:


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.




回答2:


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>"




回答3:


KeyValuePair is a struct (Implicitly Inherits from ValueType) and the Equality works just fine:

var a = new KeyValuePair<string, string>("a", "b");
var b = new KeyValuePair<string, string>("a", "b");

bool areEqual = a.Equals(b); // true

Reference below Shows the Equals Strategy:

1- Same Reference.

2- Can Compare by bits.

3- Compare each field in the struct using reflection.

 public abstract class ValueType {

        [System.Security.SecuritySafeCritical]
        public override bool Equals (Object obj) {
            BCLDebug.Perf(false, "ValueType::Equals is not fast.  "+this.GetType().FullName+" should override Equals(Object)");
            if (null==obj) {
                return false;
            }
            RuntimeType thisType = (RuntimeType)this.GetType();
            RuntimeType thatType = (RuntimeType)obj.GetType();

            if (thatType!=thisType) {
                return false;
            }

            Object thisObj = (Object)this;
            Object thisResult, thatResult;

            // if there are no GC references in this object we can avoid reflection 
            // and do a fast memcmp
            if (CanCompareBits(this))
                return FastEqualsCheck(thisObj, obj);

            FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            for (int i=0; i<thisFields.Length; i++) {
                thisResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(thisObj);
                thatResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(obj);

                if (thisResult == null) {
                    if (thatResult != null)
                        return false;
                }
                else
                if (!thisResult.Equals(thatResult)) {
                    return false;
                }
            }

            return true;
        }


来源:https://stackoverflow.com/questions/38250596/why-does-keyvaluepair-not-override-equals-and-gethashcode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!