Использование возвращаемого типа.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

Знаю это 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 свойство выставляется как член поумолчанию:

члены IDictionary

Это означает, что вы можете иметь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, а скорее рассматривает добавленные ключи как один объект, а не как итерируемый объект.

Я просто надеюсь, что кто-нибудь где-нибудь позже найдет это полезным. Спасибо вам всем.

Другие вопросы по тегам