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的主要内容,如果未能解决你的问题,请参考以下文章
C#里使用linq做多个值的GroupBy操作,被操作对象类型为List<Dictionary<string, string>> datas
性能:SortedDictionary vs SortedSet
ASP在Scripting.Dictionary对象可以用来做啥