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

原文地址:https://www.cnblogs.com/marcher/p/10150622.html

时间: 2024-11-09 00:31:24

Dictionary里使用struct,enum做key的相关文章

在firebase里不要用int做key

理由如下,经验之谈: 使用的是官方推荐的三个库之一python-firebase来取数据的

Unity3D研究之多语言用中文做KEY

 做多语言的时候用中文做KEY绝对是有100%的优点,假设用英文表示那么代码里面给文字赋值的地方全都是英文.写的代码多了以后维护起来就没有人能看懂了,或者看起来非常费劲. 对PoolManager不了解的能够看下初探PoolManager插件非常适合新手学习. 说说用中文做KEY的原理:Unity中给文字赋值的地方就两处, 一个是提前预制在UI Prefab上的文字.另一个是写在代码里面的文字.那么在开发阶段我们在Prefab和代码里面直接就写中文,等项目后期通过工具把所有中文的地方所有提取

c++模板元编程二:用enum做数值计算

2.1 用enum做数值计算 下面两篇文章都介绍了模板元编程,enum是其最重要的基本工具 http://www.codeproject.com/Articles/3743/A-gentle-introduction-to-Template-Metaprogramming https://www10.informatik.uni-erlangen.de/~pflaum/pflaum/ProSeminar/meta-art.html 因此可以得道以下结论: enum的值由编译器在编译期计算 利用模

C#中正确使用enum累做Key的姿势

C#中自定义enum,然后将其作为Dictionary的Key,通常的做法如下: using System; using System.Text; using System.Collections.Generic; namespace ConsoleApplication1 { enum ClothType { Hair, Coat, Shoes, } class Cloth { } class Program { static void Main(string[] args) { Dictio

适当使用enum做数据字典 ( .net c# winform csharp asp.net webform )

在一些应用中,通常会用到很多由一些常量来进行描述的状态数据,比如性别(男.女),审核(未审核.已审核)等.在数据库中一般用数字形式来存储,比如0.1等. 不好的做法 经常看到一些应用(ps:最近又看到)没有把这类数据整理成一个数据字典,比如经常重复这样的html: <select>     <option value="0">未审核</option>     <option value="1">已审核</opti

Java学习笔记--HashMap中使用object做key的问题【转载】

在HashMap中,如果需要使用多个属性组合作为key,可以将这几个属性组合成一个对象作为key.但是存在的问题是,要做get时,往往没办法保存当初put操作时的key object的reference,此时,需要让key object覆盖如下hashCode()和equals(Object obj)的实现.sample code如下: public class TestKeyObject { private long id; private int type; public TestKeyOb

std::map, struct pointer 为key

template < class Key, // map::key_type class T, // map::mapped_type class Compare = less<Key>, // map::key_compare class Alloc = allocator<pair<const Key,T> > // map::allocator_type > class map; struct Cell{ int x; int y; Cell(int

C# Dictionary通过value获取对应的key值

1:最直白的循环遍历方法,可以分为遍历key--value键值对以及所有的key两种表现形式 2:用Linq的方式去查询(当然了这里要添加对应的命名空间 using System.Linq) 如下为一个十分简单的代码示例: private void GetDicKeyByValue() { Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("1", "1

C# Dictionary通过value获取对应的key值[转发]

1:最直白的循环遍历方法,可以分为遍历key--value键值对以及所有的key两种表现形式 2:用Linq的方式去查询(当然了这里要添加对应的命名空间 using System.Linq) 如下为一个十分简单的代码示例: private void GetDicKeyByValue() { Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("1", "1