2017-12-01 82 views
6

W wielu językach możliwe jest sprawdzenie, czy obiekt jest możliwy do sprawdzenia, jak to zrobić dla VBA?Sprawdź, czy wartość jest iterowalna vba

mogę spróbować:

Function isIterable(obj As Variant) As Boolean 
    On Error Resume Next 
    Dim iterator As Variant 
    For Each iterator In obj 
     Exit For 
    Next 
    isIterable = Err.Number = 0 
End Function 

Ale zastanawiam się, czy istnieje wbudowane lub lepsze podejście?

+0

Należy pamiętać, że w czasie, gdy funkcja obsługuje tablice, tablice należy powtórzyć z 'For' pętli, a nie' Dla każdego "(z ważnych powodów związanych z wydajnością). Kod wywołujący powinien przetestować ten wariant za pomocą 'IsArray'. –

+0

Ale ponieważ tylko iteruje pierwszy element na liście, aby przetestować pod kątem możliwości iteracji (teraz jest to słowo!), Nie będzie to miało większego znaczenia, @ Mat'sMug. – FreeMan

+1

@FreeMan nie w * tej * funkcji - ale jeśli jakiś kod wywołuje tę funkcję, aby odkryć, czy coś może być iterowane za pomocą pętli 'For Each', a funkcja pobiera tablicę i mówi" tak, oczywiście, nie ma problemu ", to wydaje się rozsądne założenie, że kod wywołujący rozgałęzi się do pętli 'For Each' na czymkolwiek' obj'. A jeśli to tablica, to jest cholernie nieefektywna. –

Odpowiedz

4

Czy istnieje wbudowaną funkcję: nr

Czy istnieje lepsze podejście?:

bym zrobił to tak:

Function isIterable(obj As Variant) As Boolean 

    On Error GoTo isIterable_Error 

    Dim iterator As Variant 

    For Each iterator In obj 
     isIterable = True 
     Exit Function 
    Next 

isIterable_Error: 

End Function 

Ponieważ oddanie dwukrotnie = na tej samej linii jest nieco zbyt wiele.

+2

Dlaczego "przy błędzie w stanie 0" nie jest automatyczne po wyjściu z funkcji? Ponadto, czy nie podniosą Państwo błędu, pomijając ten wiersz? Myślę, że twoje podejście jest również lepsze, ponieważ nie zawiera wezwania do 'Err.Number' – Greedo

+0

@ Greedo -' On Error GoTo 0' jest nawykiem (i jest wbudowaną funkcją MZTools, której używam do błędu obsługa). Rzeczywiście, będzie bez niego również działać. A podniesienie błędu pomijałoby to, tak. W rzeczywistości linia ta nie jest dostępna w żadnym wypadku :) – Vityata

+0

Nie zgadzam się z dwukrotnym wprowadzeniem '=' jest zbyt wiele. Uważam, że łatwiej jest myśleć o tym, że błąd zwraca błąd? Umieść tę odpowiedź w zmiennej'_. Takie samo myślenie z _Boolean = Not Boolean_, aby odwrócić TRUE na FALSE i Visible to Invisible. –

2

Nie sądzę, że to lepiej niż funkcja Vityata, ale tylko jako alternatywę:

Function isIterable(obj As Object) As Boolean 

    On Error Resume Next 

    isIterable = TypeName(CallByName(obj, "_NewEnum", VbGet)) = "Unknown" 
    If Not isIterable Then isIterable = TypeName(CallByName(obj, "_NewEnum", VbMethod)) = "Unknown" 

End Function 
+0

Jedną z rzeczy, której nie obsługuje (kod OP robi) jest tablica - weź parametr 'Variant' 'Jeśli IsArray (obj) Then isIterable = True: Wyjdź z funkcji' na górze i jesteś gotowy do pracy. Również niestandardowe klasy kolekcji nie mogą mieć elementu "_NewEnum" (podkreślenie podkreślenia jest niedozwolone w identyfikatorze VBA). Ujawniam getter właściwości 'NewEnum' (nie jestem pewien, czy nazwa ma takie znaczenie jak atrybut członkowski' VB_UserMemId = -4'), więc dalsze sprawdzanie przy użyciu '" NewEnum "' dla nazwy elementu działałoby ... ale nie 100% niezawodnie. Jedynym sposobem, aby * naprawdę * to zrobić, byłoby użycie interfejsu API do refleksji. –

+0

Możesz sobie poradzić z '_' np. 'MsgBox TypeName (aCollection. [_ NewEnum])' –

+0

@AlexK. Tak, w ten sposób niestandardowe kolekcje wywołują moduł wyliczający wewnętrznej kolekcji ... mówię, że niestandardowa kolekcja może mieć właściwość "Właściwość publiczna Get NextItem() jako IUnknown" z atrybutem członka "NextItem.VB_UserMemId = -4 'i tam funkcja będzie miała fałszywy minus. IOW, w przeciwieństwie do interfejsu API do refleksji, który umożliwia zapytanie użytkownika o tę konkretną wartość atrybutu, najlepszym rozwiązaniem jest to, co ma OP. –

Powiązane problemy