Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2017
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.54 KB | None | 0 0
  1. Dictionaries 和 Enums
  2. 發生封箱一個常見的原因是使用 enum 類型作為 Dictionary 的 Key,宣告一個 enum 會建立一個新的數值類別其運作方式像是普通的整數,但在編譯時會進行類別檢查(Type-safety)。
  3.  
  4. 在預設的情況下,呼叫 Dictionary.add(key, value) 會呼叫到 Object.getHashCode(Object)。這個方法用來取得 Dictionary key 的雜湊值,它也會在 Dictionary.tryGetValue、Dictionary.remove 等等方法執行中呼叫到。
  5.  
  6. Object.getHashCode 方法是傳參考類型的,但 enum 值永遠是數值類型。因此使用 enum 作為 key 類型的 Dictionary,每次的方法呼叫會導致 key 被封箱一次以上。
  7.  
  8. 以下程式碼說明這個封箱問題
  9.  
  10. enum MyEnum { a, b, c };
  11. var myDictionary =
  12. new Dictionary<MyEnum, object>();
  13.  
  14. myDictionary.Add(MyEnum.a, new object());
  15.  
  16.  
  17. 要解決這個問題,需要編寫一個自訂類別來實做 IEqualityComparer 介面,並將該類別的實體設定作為 Dictionary 的比較器(註10)。這種物件通常不需要保存狀態,因此不同的 Dictionary 可以共用 IEqualityComparer 物件以節省記憶體。
  18.  
  19. ##########################################################################
  20.  
  21. using UnityEngine;
  22. using System.Collections;
  23. using System.Collections.Generic;
  24.  
  25. public class DictionaryAlloc : MonoBehaviour
  26. {
  27. public enum TimeZones
  28. {
  29. EST,
  30. EDT
  31. }
  32.  
  33. private Dictionary<TimeZones, float> m_allocDictionary = new Dictionary<TimeZones, float>();
  34.  
  35. private Dictionary<TimeZones, float> m_noAllocDictionary = new Dictionary<TimeZones, float>(new TimeZoneEnumCompare());
  36. private class TimeZoneEnumCompare : IEqualityComparer<TimeZones>
  37. {
  38. public bool Equals(TimeZones a, TimeZones b)
  39. {
  40. return (int)a == (int)b;
  41. }
  42.  
  43. public int GetHashCode(TimeZones a)
  44. {
  45. return (int)a;
  46. }
  47. }
  48.  
  49. private float m_dummyMath = 0;
  50. private float m_curVal = 0;
  51. private bool m_allocMode = true;
  52.  
  53. void Start ()
  54. {
  55. m_allocDictionary.Add(TimeZones.EST, 1);
  56. m_allocDictionary.Add(TimeZones.EDT, 2);
  57. m_noAllocDictionary.Add(TimeZones.EST, 1);
  58. m_noAllocDictionary.Add(TimeZones.EDT, 2);
  59. }
  60.  
  61. void Update ()
  62. {
  63. if(Input.GetKeyDown(KeyCode.Space))
  64. {
  65. m_allocMode = !m_allocMode;
  66. }
  67.  
  68. if(m_allocMode)
  69. {
  70. AccessAllocDictionary();
  71. }
  72. else
  73. {
  74. AccessNoAllocDictionary();
  75. }
  76. }
  77.  
  78. private void AccessAllocDictionary()
  79. {
  80. // ContainsKey is 60B Editor/Standalone GCAlloc
  81. if (m_allocDictionary.ContainsKey(TimeZones.EST))
  82. {
  83. m_dummyMath += 1;
  84. }
  85.  
  86. // Direct access is 60B Editor/Standalone GC Alloc
  87. m_dummyMath += m_allocDictionary[TimeZones.EDT];
  88.  
  89. // TryGetValue is 60B Editor/Standalone GC Alloc
  90. if (m_allocDictionary.TryGetValue(TimeZones.EDT, out m_curVal))
  91. {
  92. m_dummyMath += m_curVal;
  93. }
  94. }
  95.  
  96. // After writing a comparator dictionary they no longer alloc
  97. private void AccessNoAllocDictionary()
  98. {
  99. if (m_noAllocDictionary.ContainsKey(TimeZones.EST))
  100. {
  101. m_dummyMath += 1;
  102. }
  103.  
  104. m_dummyMath += m_noAllocDictionary[TimeZones.EDT];
  105.  
  106. if (m_noAllocDictionary.TryGetValue(TimeZones.EDT, out m_curVal))
  107. {
  108. m_dummyMath += m_curVal;
  109. }
  110. }
  111. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement