Использование возвращаемого типа.NET HashTable в VBA
Я создал библиотеку.NET в VB.NET, и есть функция, которая возвращает объект HashTable
,
Я искал, как получить доступ к элементам в объекте HashTable в Excel VBA, но не могу найти решение. Я новичок в VBA, так что извините. Я искал, но не могу найти выход.
Например, после чего-то подобного я не знаю, как получить доступ к данным.
Dim hashData As Object
Set hashData = obj.getHashData
Пожалуйста помоги
2 ответа
Dim hashData As Object Set hashData = obj.getHashData
Если getHashData
возвращает HashTable
, тогда hashData
поздний HashTable
и вы можете вызвать его членов, в том числе его Item
свойство:
Dim value As Variant
value = hashData.Item("key")
Вы не получаете проверку во время компиляции при вызовах участников с поздним связыванием Object
, поэтому вы должны быть особенно осторожны при опечатках, потому что Option Explicit
не может спасти вас, когда поздняя привязка участвует. Обратитесь к HashTable
приведенная выше документация, для членов которой вы можете ссылаться.
Добавление ссылки на mscorlib.tlb
(вы найдете его под C:\Windows\Microsoft.NET\Framework\v4.0.30319
или ссылаться на эквивалент из \Framework64
если ваш Excel 64-битный - битность библиотеки должна соответствовать битности хост-приложения) обычно допускает раннее связывание, но хотя эта библиотека является COM-видимой, она предназначена для использования из управляемого (.net) кода Таким образом, вы получаете доступ к этим объектам из интерфейсов - конкретные типы не предоставляют напрямую никаких членов:
Знаю это Hashtable
реализует IDictionary
интерфейс, мы можем использовать раннее связывание и получить проверку во время компиляции и IntelliSense, если мы объявим hashData As IDictionary
:
Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData.Item("foo") 'prints 42
Обратите внимание, что Item
свойство выставляется как член поумолчанию:
Это означает, что вы можете иметьItem
вызов элемента неявный, точно так же, как вы могли бы сделать с любым стандартным объектом коллекции VBA:
Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData("foo") 'prints 42
Ранний код гораздо легче написать, особенно когда вы не знакомы с задействованными типами. Однако, если проект ссылается на 64-битную среду и ваши макросы должны работать в 32-битной версии Excel, вам нужно придерживаться позднего связывания, чтобы избежать проблем связывания.
Также обратите внимание, повторяя Hashtable
объект с For Each
цикл не будет работать из-за того, как счетчики работают в VBA по сравнению с тем, как они работают в.NET; Keys
а также Values
коллекции являются объектами, реализующими ICollection
интерфейс, поэтому итерирование их также будет нетривиальным: For Each
цикл не будет работать, и в то время как вы можете настроить For i = 0 To hashData.Keys.Count - 1
, вы не можете получить элемент по индексуi
изICollection
,
Но мы знаем, что ICollection
наследуетсяIEnumerable
, а такжеIEnumerable
работает с For Each
так что мы можем разыграть Keys
сбор в IEnumerable
и итерируйте все ключи и значения следующим образом:
Dim hashData As mscorlib.IDictionary
Set hashData = obj.getHashData
Dim hashKeys As mscorlib.IEnumerable
Set hashKeys = hashData.Keys
Dim k As Variant
For Each k In hashKeys
Debug.Print k, hashData(k) 'outputs the key and its associated value
Next
Проблема в том, что вы не можете бросить IEnumerable
с поздним кодом или без ссылки на mscorlib.tlb
и позднего связывания как-то не увидит GetEnumerator
член, поэтому возникает ошибка 438:
Dim hashKeys As Object
Set hashKeys = hashData.Keys
Dim k As Variant
For Each k In hashKeys ' error 438, hashKeys isn't exposing the enumerator
Debug.Print k, hashData(k)
Next
Вывод: если вам нужен код VBA для запуска на 32- и 64-разрядных хостах, вам придется перепрыгивать через обручи, чтобы заставить работать код с поздней привязкой. Я бы рекомендовал работать с ранним связыванием с 64-битной средой, если вы работаете на 64-битном хосте, и распространять отдельную копию макроса, который ссылается на 32-битную платформу для 32-битных хостов. Немного труднее распространять, но менее болезненно, чем заставить работать код с поздним связыванием.
Я понимаю, что прошло много времени с тех пор, как об этом спросили/ответили, но, пожалуйста, позвольте мне ответить ради других, подобных мне, которые пытаются найти способ перебирать ключи HashTable (в VBIDE VBA).
Прочитав ответ Матье Гиндона (который довольно потрясающий) и это , а также это , я хотел бы представить свои 2 цента за то, что мы можем сделать это без необходимости добавлять ссылки и позднюю привязку (также работая внутри непосредственного окна VBA).
Как показано на прикрепленном снимке экрана, нам просто нужно добавить ключи HashTable в ArrayList, используя метод .AddRange этого ArrayList, например:
ArrayList.AddRange HashTable.Keys
Здесь об этом тоже упоминалось .
Поскольку свойство Keys HashTable является ICollection, а метод AddRange ArrayList также работает с ICollection, они подобны совпадению, заключенному на небесах, и вуаля, теперь мы можем перебирать ключи HashTable, хотя и окольным путем, как ArrayList.
Я получил эту идею из того, что здесь упоминалось об использовании очереди Queue для добавления диапазона значений в ArrayList. Однако этот метод не позволяет выполнять итерацию с использованием For Each в VBA, а скорее рассматривает добавленные ключи как один объект, а не как итерируемый объект.
Я просто надеюсь, что кто-нибудь где-нибудь позже найдет это полезным. Спасибо вам всем.