2017-12-01 21 views
6

Trong nhiều ngôn ngữ có thể kiểm tra xem một đối tượng có thể lặp lại hay không, làm cách nào để thực hiện điều này cho VBA?Kiểm tra xem giá trị có thể lặp lại vba

tôi có thể thử:

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 

Nhưng tôi tự hỏi, nếu có một dựng sẵn hoặc một cách tiếp cận tốt hơn?

+0

Lưu ý rằng trong khi chức năng của bạn hỗ trợ mảng, mảng nên được lặp với một 'loop For', không phải là một ' Đối với mỗi '(vì lý do hiệu suất đáng kể). Mã gọi điện thoại nên kiểm tra biến thể đó với 'IsArray' thay thế. –

+0

Nhưng vì anh ta chỉ lặp lại mục đầu tiên trong danh sách để kiểm tra khả năng lặp lại (bây giờ là một từ!), Nó sẽ không quan trọng lắm, @ Mat'sMug. – FreeMan

+1

@FreeMan không có chức năng * that * - nhưng nếu một số mã đang gọi hàm này để khám phá xem có thể lặp lại điều gì đó với vòng lặp 'For Each' hay không, và hàm sẽ nhận một mảng và nói" yeah sure ". có vẻ hợp lý để giả định rằng mã gọi sẽ phân nhánh thành một vòng lặp 'For Each' trên bất kỳ' obj' nào. Và nếu đó là một mảng, thì nó không hiệu quả. –

Trả lời

4

Có một built-in chức năng: số

Có một cách tiếp cận tốt hơn?:

tôi sẽ thực hiện nó như thế này:

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 

Bởi vì đặt hai lần = trên cùng một dòng là một chút quá nhiều.

+2

Tại sao 'On Error Goto 0', không phải là tự động khi thoát khỏi một hàm? Ngoài ra, sẽ không gây ra lỗi khi bỏ qua dòng đó? Tôi nghĩ rằng cách tiếp cận của bạn cũng tốt hơn ở chỗ nó không liên quan đến một cuộc gọi đến 'Err.Number' – Greedo

+0

@Greedo -' Trên Error GoTo 0' là một thói quen (và được xây dựng trong chức năng từ MZTools, mà tôi sử dụng cho lỗi xử lý). Thật vậy, nó sẽ chạy mà không có nó là tốt. Và việc đưa ra một lỗi sẽ bỏ qua nó, vâng. Như một vấn đề của thực tế dòng này là không thể truy cập trong mọi trường hợp :) – Vityata

+0

Phải không đồng ý với việc đặt '=' hai lần là quá nhiều. Tôi thấy dễ dàng hơn khi nghĩ đến lỗi _is trả về lỗi? Đặt câu trả lời đó vào một biến'_. Suy nghĩ tương tự với _Boolean = Không Boolean_ để lật TRUE thành FALSE và Hiển thị thành Ẩn. –

2

Tôi không nghĩ rằng đó là bất kỳ tốt hơn so với chức năng Vityata, nhưng cũng giống như một sự thay thế:

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

Một điều mà điều này không xử lý (mã của OP) là mảng - lấy tham số 'Biến thể 'và dính 'Nếu IsArray (obj) Sau đó isIterable = True: Exit Function' ở phía trên và bạn tốt để đi. Ngoài ra các lớp sưu tập tùy chỉnh không thể có một thành viên '_NewEnum' (tiền tố gạch dưới là bất hợp pháp trong một định danh VBA). Tôi trưng ra một thuộc tính 'NewEnum' getter (không chắc tên này quan trọng như thuộc tính thành viên' VB_UserMemId = -4'), vì vậy việc kiểm tra thêm bằng cách sử dụng '" NewEnum "' cho tên thành viên sẽ hoạt động ... nhưng không phải 100% đáng tin cậy. Cách duy nhất để * thực sự * làm điều này sẽ là với một số API phản chiếu. –

+0

Bạn có thể xử lý '_' ví dụ: 'MsgBox TypeName (aCollection. [_ NewEnum])' –

+0

@AlexK. Vâng, đó là cách các bộ sưu tập tùy chỉnh gọi bộ đếm nội bộ của họ ... những gì tôi đang nói là một bộ sưu tập tùy chỉnh có thể có một 'Property Property Get NextItem() như IUnknown' với thuộc tính thành viên' NextItem.VB_UserMemId = -4 'và ở đó, hàm sẽ có giá trị âm sai. IOW, thiếu sử dụng một API phản chiếu cho phép truy vấn một thành viên cho giá trị thuộc tính cụ thể đó, giải pháp tốt nhất là những gì mà OP có. –

Các vấn đề liên quan