Dictionary里使用struct,enum做key

Posted marcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dictionary里使用struct,enum做key相关的知识,希望对你有一定的参考价值。

首先看下Dictionary的源码

public void Add (TKey key, TValue value)
		{
			if (key == null)
				throw new ArgumentNullException ("key");

			// get first item of linked list corresponding to given key
			int hashCode = hcp.GetHashCode (key) | HASH_FLAG;
			int index = (hashCode & int.MaxValue) % table.Length;
			int cur = table [index] - 1;

			// walk linked list until end is reached (throw an exception if a
			// existing slot is found having an equivalent key)
			while (cur != NO_SLOT) {
				// The ordering is important for compatibility with MS and strange
				// Object.Equals () implementations
				if (linkSlots [cur].HashCode == hashCode && hcp.Equals (keySlots [cur], key))
					throw new ArgumentException ("An element with the same key already exists in the dictionary.");
				cur = linkSlots [cur].Next;
			}

			if (++count > threshold) {
				Resize ();
				index = (hashCode & int.MaxValue) % table.Length;
			}
			
			// find an empty slot
			cur = emptySlot;
			if (cur == NO_SLOT)
				cur = touchedSlots++;
			else 
				emptySlot = linkSlots [cur].Next;

			// store the hash code of the added item,
			// prepend the added item to its linked list,
			// update the hash table
			linkSlots [cur].HashCode = hashCode;
			linkSlots [cur].Next = table [index] - 1;
			table [index] = cur + 1;

			// store item‘s data 
			keySlots [cur] = key;
			valueSlots [cur] = value;

			generation++;
		}

  

int hashCode = hcp.GetHashCode (key) | HASH_FLAG;

hcp

[Serializable]
        sealed class DefaultComparer : EqualityComparer<T> {
    
            public override int GetHashCode (T obj)
            {
                if (obj == null)
                    return 0;
                return obj.GetHashCode ();
            }
    
            public override bool Equals (T x, T y)
            {
                if (x == null)
                    return y == null;
                
                return x.Equals (y);
            }
        }

其实就是走到obj.GetHashCode,如果obj.GetHashCode没有覆盖的话,那就会走到ValueType的GetHashCode

public override int GetHashCode ()
        {
            object[] fields;
            int result = InternalGetHashCode (this, out fields);

            if (fields != null)
                for (int i = 0; i < fields.Length; ++i)
                    if (fields [i] != null)
                        result ^= fields [i].GetHashCode ();
                
            return result;
        }

注意看

[MethodImplAttribute (MethodImplOptions.InternalCall)]
        internal extern static int InternalGetHashCode (object o, out object[] fields);
int result = InternalGetHashCode (this, out fields);
会把this转成object类型,第1次boxing,而且会把每个字段都转成object,放入fields里,所以会有多次gc alloc
这个是不重载GetHashCode导致的gc alloc。
下一个是
if (linkSlots [cur].HashCode == hashCode && hcp.Equals (keySlots [cur], key))

hcp.Equals

技术分享图片

如果T没有实现IEquatable,就会走到DefaultCOmparer,然后会走到

技术分享图片

这个Equals会调用ValueType.Equals

internal static bool DefaultEquals (object o1, object o2)
        {
            object[] fields;

            if (o2 == null)
                return false;

            bool res = InternalEquals (o1, o2, out fields);
            if (fields == null)
                return res;

            for (int i = 0; i < fields.Length; i += 2) {
                object meVal = fields [i];
                object youVal = fields [i + 1];
                if (meVal == null) {
                    if (youVal == null)
                        continue;

                    return false;
                }

                if (!meVal.Equals (youVal))
                    return false;
            }

            return true;
        }

        // <summary>
        //   True if this instance and o represent the same type
        //   and have the same value.
        // </summary>
        public override bool Equals (object obj)
        {
            return DefaultEquals (this, obj);
        }

这个里面会把x,y都转成object.所以会有2次boxing

至此所有的boxing都清楚了,工程例子在

https://github.com/yingsz/DictionaryAlloc

消除boxing参考

http://www.bkjia.com/Asp_Netjc/1314145.html




以上是关于Dictionary里使用struct,enum做key的主要内容,如果未能解决你的问题,请参考以下文章

Enum 枚举转 Dictionary字典

类型 '()' 不能符合 'View';只有 struct/enum/class 类型可以符合使用 swift ui 调用调用函数的协议

如何将 Dictionary<enum, bool> 双向绑定到 WPF 中的 ListView 列?

C#在Dictionary中使用枚举作为键

Swift 5 从Model, Struct或Class转Dictionary

enum和struct的用法-----c#