Class Dictionary не могу понять как работает модуль
#39730132
Ссылка:
Ссылка на сообщение:
Ссылка с названием темы:
|
|
|
С гит-хаба был стырен кусок кода:
Dictionary 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377. 378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388. 389. 390. 391. 392. 393. 394. 395. 396. 397. 398. 399. 400. 401. 402. 403. 404. 405. 406. 407. 408. 409. 410. 411. 412. 413. 414. 415. 416. 417. 418. 419. 420. 421. 422. 423. 424. 425. 426. 427. 428. 429. 430. 431. 432. 433. 434. 435. 436. 437. 438. 439. 440. 441. 442. 443. 444. 445. 446. 447. 448. 449. 450. 451. 452. 453. 454. 455. 456. 457. 458. 459. 460. 461. 462. 463. 464. 465. 466.
''
' Dictionary v1.4.1
' (c) Tim Hall - https://github.com/timhall/VBA-Dictionary
'
' Drop-in replacement for Scripting.Dictionary on Mac
'
' @author: tim.hall.engr@gmail.com
' @license: MIT (http://www.opensource.org/licenses/mit-license.php
'
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ '
Option Explicit
' --------------------------------------------- '
' Constants and Private Variables
' --------------------------------------------- '
#Const UseScriptingDictionaryIfAvailable = True
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
' dict_KeyValue 0: FormattedKey, 1: OriginalKey, 2: Value
Private dict_pKeyValues As Collection
Private dict_pKeys() As Variant
Private dict_pItems() As Variant
Private dict_pObjectKeys As Collection
Private dict_pCompareMode As CompareMethod
#Else
Private dict_pDictionary As Object
#End If
' --------------------------------------------- '
' Types
' --------------------------------------------- '
Public Enum CompareMethod
BinaryCompare = VBA.vbBinaryCompare
TextCompare = VBA.vbTextCompare
DatabaseCompare = VBA.vbDatabaseCompare
End Enum
' --------------------------------------------- '
' Properties
' --------------------------------------------- '
Public Property Get CompareMode() As CompareMethod
'Attribute CompareMode.VB_Description = "Set or get the string comparison method."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
CompareMode = dict_pCompareMode
#Else
CompareMode = dict_pDictionary.CompareMode
#End If
End Property
Public Property Let CompareMode(Value As CompareMethod)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Count > 0 Then
' Can't change CompareMode for Dictionary that contains data
' http://msdn.microsoft.com/en-us/library/office/gg278481(v=office.15).aspx
Err.Raise 5 ' Invalid procedure call or argument
End If
dict_pCompareMode = Value
#Else
dict_pDictionary.CompareMode = Value
#End If
End Property
Public Property Get Count() As Long
'Attribute Count.VB_Description = "Get the number of items in the dictionary.\n"
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Count = dict_pKeyValues.Count
#Else
Count = dict_pDictionary.Count
#End If
End Property
Public Property Get Item(Key As Variant) As Variant
'Attribute Item.VB_Description = "Set or get the item for a given key."
'Attribute Item.VB_UserMemId = 0
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Dim dict_KeyValue As Variant
dict_KeyValue = dict_GetKeyValue(Key)
If Not IsEmpty(dict_KeyValue) Then
If VBA.IsObject(dict_KeyValue(2)) Then
Set Item = dict_KeyValue(2)
Else
Item = dict_KeyValue(2)
End If
Else
' Not found -> Returns Empty
End If
#Else
If VBA.IsObject(dict_pDictionary.Item(Key)) Then
Set Item = dict_pDictionary.Item(Key)
Else
Item = dict_pDictionary.Item(Key)
End If
#End If
End Property
Public Property Let Item(Key As Variant, Value As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Exists(Key) Then
dict_ReplaceKeyValue dict_GetKeyValue(Key), Key, Value
Else
dict_AddKeyValue Key, Value
End If
#Else
dict_pDictionary.Item(Key) = Value
#End If
End Property
Public Property Set Item(Key As Variant, Value As Variant)
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Exists(Key) Then
dict_ReplaceKeyValue dict_GetKeyValue(Key), Key, Value
Else
dict_AddKeyValue Key, Value
End If
#Else
Set dict_pDictionary.Item(Key) = Value
#End If
End Property
Public Property Let Key(Previous As Variant, Updated As Variant)
'Attribute Key.VB_Description = "Change a key to a different key."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Dim dict_KeyValue As Variant
dict_KeyValue = dict_GetKeyValue(Previous)
If Not VBA.IsEmpty(dict_KeyValue) Then
dict_ReplaceKeyValue dict_KeyValue, Updated, dict_KeyValue(2)
End If
#Else
dict_pDictionary.Key(Previous) = Updated
#End If
End Property
' ============================================= '
' Public Methods
' ============================================= '
''
' Add an item with the given key
'
' @param {Variant} Key
' @param {Variant} Item
' --------------------------------------------- '
Public Sub Add(Key As Variant, Item As Variant)
'Attribute Add.VB_Description = "Add a new key and item to the dictionary."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Not Me.Exists(Key) Then
dict_AddKeyValue Key, Item
Else
' This key is already associated with an element of this collection
Err.Raise 457
End If
#Else
dict_pDictionary.Add Key, Item
#End If
End Sub
''
' Check if an item exists for the given key
'
' @param {Variant} Key
' @return {Boolean}
' --------------------------------------------- '
Public Function Exists(Key As Variant) As Boolean
'Attribute Exists.VB_Description = "Determine if a given key is in the dictionary."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Exists = Not IsEmpty(dict_GetKeyValue(Key))
#Else
Exists = dict_pDictionary.Exists(Key)
#End If
End Function
''
' Get an array of all items
'
' @return {Variant}
' --------------------------------------------- '
Public Function Items() As Variant
'Attribute Items.VB_Description = "Get an array containing all items in the dictionary."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Count > 0 Then
Items = dict_pItems
Else
' Split("") creates initialized empty array that matches Dictionary Keys and Items
Items = VBA.Split("")
End If
#Else
Items = dict_pDictionary.Items
#End If
End Function
''
' Get an array of all keys
'
' @return {Variant}
' --------------------------------------------- '
Public Function Keys() As Variant
'Attribute Keys.VB_Description = "Get an array containing all keys in the dictionary."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
If Me.Count > 0 Then
Keys = dict_pKeys
Else
' Split("") creates initialized empty array that matches Dictionary Keys and Items
Keys = VBA.Split("")
End If
#Else
Keys = dict_pDictionary.Keys
#End If
End Function
''
' Remove an item for the given key
'
' @param {Variant} Key
' --------------------------------------------- '
Public Sub Remove(Key As Variant)
'Attribute Remove.VB_Description = "Remove a given key from the dictionary."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Dim dict_KeyValue As Variant
dict_KeyValue = dict_GetKeyValue(Key)
If Not VBA.IsEmpty(dict_KeyValue) Then
dict_RemoveKeyValue dict_KeyValue
Else
' Application-defined or object-defined error
Err.Raise 32811
End If
#Else
dict_pDictionary.Remove Key
#End If
End Sub
''
' Remove all items
' --------------------------------------------- '
Public Sub RemoveAll()
'Attribute RemoveAll.VB_Description = "Remove all information from the dictionary."
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Set dict_pKeyValues = New Collection
Erase dict_pKeys
Erase dict_pItems
#Else
dict_pDictionary.RemoveAll
#End If
End Sub
' ============================================= '
' Private Functions
' ============================================= '
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Private Function dict_GetKeyValue(dict_Key As Variant) As Variant
On Error Resume Next
dict_GetKeyValue = dict_pKeyValues(dict_GetFormattedKey(dict_Key))
Err.Clear
End Function
Private Sub dict_AddKeyValue(dict_Key As Variant, dict_Value As Variant, Optional dict_Index As Long = -1)
If Me.Count = 0 Then
ReDim dict_pKeys(0 To 0)
ReDim dict_pItems(0 To 0)
Else
ReDim Preserve dict_pKeys(0 To UBound(dict_pKeys) + 1)
ReDim Preserve dict_pItems(0 To UBound(dict_pItems) + 1)
End If
Dim dict_FormattedKey As String
dict_FormattedKey = dict_GetFormattedKey(dict_Key)
If dict_Index >= 0 And dict_Index < dict_pKeyValues.Count Then
' Shift keys/items after + including index into empty last slot
Dim dict_i As Long
For dict_i = UBound(dict_pKeys) To dict_Index + 1 Step -1
dict_pKeys(dict_i) = dict_pKeys(dict_i - 1)
If VBA.IsObject(dict_pItems(dict_i - 1)) Then
Set dict_pItems(dict_i) = dict_pItems(dict_i - 1)
Else
dict_pItems(dict_i) = dict_pItems(dict_i - 1)
End If
Next dict_i
' Add key/item at index
dict_pKeys(dict_Index) = dict_Key
If VBA.IsObject(dict_Value) Then
Set dict_pItems(dict_Index) = dict_Value
Else
dict_pItems(dict_Index) = dict_Value
End If
' Add key-value at proper index
dict_pKeyValues.Add Array(dict_FormattedKey, dict_Key, dict_Value), dict_FormattedKey, Before:=dict_Index + 1
Else
' Add key-value as last item
If VBA.IsObject(dict_Key) Then
Set dict_pKeys(UBound(dict_pKeys)) = dict_Key
Else
dict_pKeys(UBound(dict_pKeys)) = dict_Key
End If
If VBA.IsObject(dict_Value) Then
Set dict_pItems(UBound(dict_pItems)) = dict_Value
Else
dict_pItems(UBound(dict_pItems)) = dict_Value
End If
dict_pKeyValues.Add Array(dict_FormattedKey, dict_Key, dict_Value), dict_FormattedKey
End If
End Sub
Private Sub dict_ReplaceKeyValue(dict_KeyValue As Variant, dict_Key As Variant, dict_Value As Variant)
Dim dict_Index As Long
Dim dict_i As Integer
dict_Index = dict_GetKeyIndex(dict_KeyValue(1))
' Remove existing dict_Value
dict_RemoveKeyValue dict_KeyValue, dict_Index
' Add new dict_Key dict_Value back
dict_AddKeyValue dict_Key, dict_Value, dict_Index
End Sub
Private Sub dict_RemoveKeyValue(dict_KeyValue As Variant, Optional ByVal dict_Index As Long = -1)
Dim dict_i As Long
If dict_Index = -1 Then
dict_Index = dict_GetKeyIndex(dict_KeyValue(1))
End If
If dict_Index >= 0 And dict_Index <= UBound(dict_pKeys) Then
' Shift keys/items after index down
For dict_i = dict_Index To UBound(dict_pKeys) - 1
dict_pKeys(dict_i) = dict_pKeys(dict_i + 1)
If VBA.IsObject(dict_pItems(dict_i + 1)) Then
Set dict_pItems(dict_i) = dict_pItems(dict_i + 1)
Else
dict_pItems(dict_i) = dict_pItems(dict_i + 1)
End If
Next dict_i
' Resize keys/items to remove empty slot
If UBound(dict_pKeys) = 0 Then
Erase dict_pKeys
Erase dict_pItems
Else
ReDim Preserve dict_pKeys(0 To UBound(dict_pKeys) - 1)
ReDim Preserve dict_pItems(0 To UBound(dict_pItems) - 1)
End If
End If
dict_pKeyValues.Remove dict_KeyValue(0)
dict_RemoveObjectKey dict_KeyValue(1)
End Sub
Private Function dict_GetFormattedKey(dict_Key As Variant) As String
If VBA.IsObject(dict_Key) Then
dict_GetFormattedKey = dict_GetObjectKey(dict_Key)
ElseIf VarType(dict_Key) = VBA.vbBoolean Then
dict_GetFormattedKey = IIf(dict_Key, "-1__-1", "0__0")
ElseIf VarType(dict_Key) = VBA.vbString Then
dict_GetFormattedKey = dict_Key
If Me.CompareMode = CompareMethod.BinaryCompare Then
' Collection does not have method of setting key comparison
' So case-sensitive keys aren't supported by default
' -> Approach: Append lowercase characters to original key
' AbC -> AbC___b_, abc -> abc__abc, ABC -> ABC_____
Dim dict_Lowercase As String
dict_Lowercase = ""
Dim dict_i As Integer
Dim dict_Char As String
Dim dict_Ascii As Integer
For dict_i = 1 To VBA.Len(dict_GetFormattedKey)
dict_Char = VBA.Mid$(dict_GetFormattedKey, dict_i, 1)
dict_Ascii = VBA.Asc(dict_Char)
If dict_Ascii >= 97 And dict_Ascii <= 122 Then
dict_Lowercase = dict_Lowercase & dict_Char
Else
dict_Lowercase = dict_Lowercase & "_"
End If
Next dict_i
If dict_Lowercase <> "" Then
dict_GetFormattedKey = dict_GetFormattedKey & "__" & dict_Lowercase
End If
End If
Else
' For numbers, add duplicate to distinguish from strings
' -> 123 -> "123__123"
' "123" -> "123"
dict_GetFormattedKey = VBA.CStr(dict_Key) & "__" & CStr(dict_Key)
End If
End Function
Private Function dict_GetObjectKey(dict_ObjKey As Variant) As String
Dim dict_i As Integer
For dict_i = 1 To dict_pObjectKeys.Count
If dict_pObjectKeys.Item(dict_i) Is dict_ObjKey Then
dict_GetObjectKey = "__object__" & dict_i
Exit Function
End If
Next dict_i
dict_pObjectKeys.Add dict_ObjKey
dict_GetObjectKey = "__object__" & dict_pObjectKeys.Count
End Function
Private Sub dict_RemoveObjectKey(dict_ObjKey As Variant)
Dim dict_i As Integer
For dict_i = 1 To dict_pObjectKeys.Count
If dict_pObjectKeys.Item(dict_i) Is dict_ObjKey Then
dict_pObjectKeys.Remove dict_i
Exit Sub
End If
Next dict_i
End Sub
Private Function dict_GetKeyIndex(dict_Key As Variant) As Long
Dim dict_i As Long
For dict_i = 0 To UBound(dict_pKeys)
If VBA.IsObject(dict_pKeys(dict_i)) And VBA.IsObject(dict_Key) Then
If dict_pKeys(dict_i) Is dict_Key Then
dict_GetKeyIndex = dict_i
Exit For
End If
ElseIf VBA.IsObject(dict_pKeys(dict_i)) Or VBA.IsObject(dict_Key) Then
' Both need to be objects to check equality, skip
ElseIf dict_pKeys(dict_i) = dict_Key Then
dict_GetKeyIndex = dict_i
Exit For
End If
Next dict_i
End Function
#End If
Private Sub Class_Initialize()
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Set dict_pKeyValues = New Collection
Erase dict_pKeys
Erase dict_pItems
Set dict_pObjectKeys = New Collection
#Else
Set dict_pDictionary = CreateObject("Scripting.Dictionary")
#End If
End Sub
Private Sub Class_Terminate()
#If Mac Or Not UseScriptingDictionaryIfAvailable Then
Set dict_pKeyValues = Nothing
Set dict_pObjectKeys = Nothing
#Else
Set dict_pDictionary = Nothing
#End If
End Sub
А в другом модуле идёт инициализация этого класса
типа так 1. 2. 3. 4. 5. 6.
Public Function CreateKeyValue(Key As String, Value As Variant) As Dictionary
Dim web_KeyValue As New Dictionary
web_KeyValue("Key") = Key
web_KeyValue("Value") = Value
End Function
И вот такое обращение:
см.: web_KeyValue("Key") 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29.
''
' Convert `Dictionary`/`Collection` to Url-Encoded string.
'
' @method ConvertToUrlEncoded
' @param {Dictionary|Collection|Variant} Obj Value to convert to Url-Encoded string
' @return {String} UrlEncoded string (e.g. a=123&b=456&...)
''
Public Function ConvertToUrlEncoded(Obj As Variant, Optional EncodingMode As UrlEncodingMode = UrlEncodingMode.FormUrlEncoding) As String
Dim web_Encoded As String
Dim i As Integer
If TypeOf Obj Is Collection Then
Dim web_KeyValue As Dictionary
For Each web_KeyValue In Obj
If VBA.Len(web_Encoded) > 0 Then: web_Encoded = web_Encoded & "&"
web_Encoded = web_Encoded & web_GetUrlEncodedKeyValue(web_KeyValue("Key"), web_KeyValue("Value"), EncodingMode)
Next web_KeyValue
Else
Dim web_Key As Variant
For Each web_Key In Obj.Keys()
If Len(web_Encoded) > 0 Then: web_Encoded = web_Encoded & "&"
web_Encoded = web_Encoded & web_GetUrlEncodedKeyValue(web_Key, Obj(web_Key), EncodingMode)
Next web_Key
End If
ConvertToUrlEncoded = web_Encoded
End Function
И вот то ли я тупой, то ли незнаю... Подскажите, как мне дописать модуль класса чтобы работали эти конструкции?
Может, у кого есть готовый? Я так понимаю, этот класс часто используется...
|
|