繁体   English   中英

为什么KeyValuePair不会覆盖Equals()和GetHashCode()?

[英]Why does KeyValuePair not override Equals() and GetHashCode()?

我打算在比较密集的代码中使用KeyValuePair ,并且很困惑地检查它是如何在.NET中实现的(s。下面)

为什么它不会为了效率而重写EqualsGetHashCode (而不是实现== ),而是使用基于慢反射的默认实现?

我知道结构/值类型有一个基于其GetHashCode()Equals(object)方法的反射的默认实现,但我认为如果你做了很多比较,那么与覆盖相等相比它是非常低效的。


编辑我做了一些测试,发现在我的场景(WPF列表)中,默认的KeyValuePair和我自己的结构覆盖GetHashCode()Equals(object)的实现都比作为类的实现慢得多!


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)在某些情况下不是特别有效,并且(2)可以进行逐位比较,因此可以做到比较负零和正零双精度在逻辑上它们相等时的不同。

如果您希望您的结构经常在需要相等和散列的上下文中使用,那么您应该编写两者的自定义实现并遵循相应的规则和指南。

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

所以,回答你的问题:为什么没有人这样做? 可能是因为他们不相信这样做是为了充分利用他们的时间,而不是他们为改进基类库而必须做的所有其他事情。 大多数人不会将键值对进行比较,因此优化它可能不是一个高优先级。

这当然是推测的; 如果你真的想知道为什么有些东西没有得到在某一天做的原因,你将要追查所有没有做那个动作,问他们还有什么他们正在做的人是更重要那天。

它是一个结构,Structs继承自ValueType ,该类型已经覆盖了Equals和GetHashCode的实现

它不支持== ,执行以下操作甚至不会编译

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

您将收到错误“Operator'=='无法应用于KeyValuePair<string, string>类型的操作数KeyValuePair<string, string>KeyValuePair<string, string>

KeyValuePair是一个结构(隐式继承自ValueType ),Equality工作得很好:

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

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

以下参考显示等于策略:

1-相同参考。

2-可以按位比较。

3-使用反射比较结构中的每个字段。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM