Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Dictionaries 和 Enums
- 發生封箱一個常見的原因是使用 enum 類型作為 Dictionary 的 Key,宣告一個 enum 會建立一個新的數值類別其運作方式像是普通的整數,但在編譯時會進行類別檢查(Type-safety)。
- 在預設的情況下,呼叫 Dictionary.add(key, value) 會呼叫到 Object.getHashCode(Object)。這個方法用來取得 Dictionary key 的雜湊值,它也會在 Dictionary.tryGetValue、Dictionary.remove 等等方法執行中呼叫到。
- Object.getHashCode 方法是傳參考類型的,但 enum 值永遠是數值類型。因此使用 enum 作為 key 類型的 Dictionary,每次的方法呼叫會導致 key 被封箱一次以上。
- 以下程式碼說明這個封箱問題
- enum MyEnum { a, b, c };
- var myDictionary =
- new Dictionary<MyEnum, object>();
- myDictionary.Add(MyEnum.a, new object());
- 要解決這個問題,需要編寫一個自訂類別來實做 IEqualityComparer 介面,並將該類別的實體設定作為 Dictionary 的比較器(註10)。這種物件通常不需要保存狀態,因此不同的 Dictionary 可以共用 IEqualityComparer 物件以節省記憶體。
- ##########################################################################
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- public class DictionaryAlloc : MonoBehaviour
- {
- public enum TimeZones
- {
- EST,
- EDT
- }
- private Dictionary<TimeZones, float> m_allocDictionary = new Dictionary<TimeZones, float>();
- private Dictionary<TimeZones, float> m_noAllocDictionary = new Dictionary<TimeZones, float>(new TimeZoneEnumCompare());
- private class TimeZoneEnumCompare : IEqualityComparer<TimeZones>
- {
- public bool Equals(TimeZones a, TimeZones b)
- {
- return (int)a == (int)b;
- }
- public int GetHashCode(TimeZones a)
- {
- return (int)a;
- }
- }
- private float m_dummyMath = 0;
- private float m_curVal = 0;
- private bool m_allocMode = true;
- void Start ()
- {
- m_allocDictionary.Add(TimeZones.EST, 1);
- m_allocDictionary.Add(TimeZones.EDT, 2);
- m_noAllocDictionary.Add(TimeZones.EST, 1);
- m_noAllocDictionary.Add(TimeZones.EDT, 2);
- }
- void Update ()
- {
- if(Input.GetKeyDown(KeyCode.Space))
- {
- m_allocMode = !m_allocMode;
- }
- if(m_allocMode)
- {
- AccessAllocDictionary();
- }
- else
- {
- AccessNoAllocDictionary();
- }
- }
- private void AccessAllocDictionary()
- {
- // ContainsKey is 60B Editor/Standalone GCAlloc
- if (m_allocDictionary.ContainsKey(TimeZones.EST))
- {
- m_dummyMath += 1;
- }
- // Direct access is 60B Editor/Standalone GC Alloc
- m_dummyMath += m_allocDictionary[TimeZones.EDT];
- // TryGetValue is 60B Editor/Standalone GC Alloc
- if (m_allocDictionary.TryGetValue(TimeZones.EDT, out m_curVal))
- {
- m_dummyMath += m_curVal;
- }
- }
- // After writing a comparator dictionary they no longer alloc
- private void AccessNoAllocDictionary()
- {
- if (m_noAllocDictionary.ContainsKey(TimeZones.EST))
- {
- m_dummyMath += 1;
- }
- m_dummyMath += m_noAllocDictionary[TimeZones.EDT];
- if (m_noAllocDictionary.TryGetValue(TimeZones.EDT, out m_curVal))
- {
- m_dummyMath += m_curVal;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement