Déterminer le type complet d'une variable

Par le de type complet d'une variable je veux dire le genre d'information que vous obtenez dans la fenêtre exécution:

Déterminer le type complet d'une variable

Je tiens à déterminer le type d'informations de manière dynamique à l'aide de VBA. La fonction TypeName() ne pas faire ce que je veux car il renvoie la sous-type d'une variante et ne fait pas la distinction entre, par exemple, une variable de type variant tenant un éventail, une variable objet la tenue d'une gamme, et une variable de portée tenant un éventail.

Comme une étape préliminaire, j'ai écrit une fonction qui détecte si une variante est passé. Il fonctionne par l'exploitation par référence à la sémantique. Le code fait les choses avec son argument qui ne peut être fait avec une variante et ainsi déclencher une erreur si la variable n'est pas en fait une variante:

Function IsVariant(var As Variant) As Boolean
    Dim temp As Variant
    Dim isVar As Boolean

    If IsObject(var) Then
        Set temp = var
    Else
        temp = var
    End If

    On Error Resume Next
        Set var = New Collection
        var = "test"
        If Err.Number > 0 Then
            isVar = False
        Else
            isVar = True
        End If
    On Error GoTo 0

    If IsObject(temp) Then
        Set var = temp
    Else
        var = temp
    End If
    IsVariant = isVar
End Function

Sur cette base, j'ai écrit:

Function FullType(var As Variant) As String
    If IsVariant(var) Then
        FullType = "Variant/" & TypeName(var)
    Else
        FullType = TypeName(var)
    End If
End Function

Code de test:

Sub TestTypes()
    Dim R As Range
    Dim Ob As Object
    Dim i As Integer
    Dim v1 As Variant
    Dim v2 As Variant

    v1 = 10
    i = 10

    Set v2 = Range("A1")
    Set Ob = Range("A2")
    Set R = Range("A3")

    Debug.Print "v1: " & FullType(v1)
    Debug.Print "i: " & FullType(i)
    Debug.Print "v2: " & FullType(v2)
    Debug.Print "Ob: " & FullType(Ob)
    Debug.Print "R: " & FullType(R)  
End Sub

De sortie:

v1: Variant/Integer
i: Integer
v2: Variant/Range
Ob: Range
R: Range

C'est presque ce que je veux-mais ne fait pas la distinction entre une variable objet la tenue d'une gamme et une gamme variable tenant un éventail. J'ai essayé d'écrire une fonction appelée IsTypeObject qui fonctionne de façon similaire à IsVariant mais n'arrive pas à le faire fonctionner:

Function IsTypeObject(var As Variant) As Boolean
    Dim temp As Variant
    Dim isGeneric As Boolean

    If (Not IsObject(var)) Or IsVariant(var) Then
        IsTypeObject = False
        Exit Function
    End If

    Set temp = var
    On Error Resume Next
        Set var = New Collection
        Set var = ActiveWorkbook
        If Err.Number > 0 Then
            isGeneric = False
        Else
            isGeneric = True
        End If
    On Error GoTo 0

    Set var = temp
    IsTypeObject = isGeneric
End Function

Test:

Sub test()
    Dim R As Range
    Set R = Range("A1")
    Debug.Print IsTypeObject(R)
End Sub

Mais cela s'imprime True même si je pense que le même passé par référence sémantique qui rend IsVariant travail devrait également faire IsTypeObject de travail (vous ne pouvez pas affecter une collection d'une gamme). J'ai essayé différents réglages mais ne semble pas possible de distinguer entre le générique des variables d'objet et d'objet spécifique des variables comme variables de portée.

Donc -- des idées pour comment dynamiquement pour obtenir le plein type d'une variable? (La motivation est, dans le cadre d'un debug log utilitaire)

  • La variante par les ouvrages de référence parce que le VARIANT struct a la VT_BYREF drapeau qui peut ou peut ne pas être défini. Il n'y a rien de tel pour les non-variables de type Variant. Vous avez réflexion .NET, mais pas en VBA.
  • La chose étrange est que, même dans le cas de mon "succès" IsVariant, lorsque je passe un Range variable et de regarder où l'erreur se pose en marchant à travers elle dans le débogueur, la ligne Set var = New Collection ne fait pas déclencher l'erreur, la ligne suivante lorsque j'essaie d'assigner une chaîne, c'est quelles sont les causes de l'erreur que je suis de piégeage. Je pense que VBA doit mettre en œuvre passe par référence par l'intermédiaire d'une sorte de copier-méthode de restauration -- mais alors, il devient étrange que la ligne suivante provoque une erreur (par opposition à une incompatibilité de type de retour).
  • C'est parce que quand un objet est utilisé dans un contexte de valeurs, VB essaie d'utiliser le par défaut de la propriété de l'objet à la place. À condition que var est un objet, var = "test" essaie d'assigner "test" à la propriété par défaut de var, et il n'en a pas (erreur 438, ce qui n'est pas une erreur d'incompatibilité de type).
  • Je pense que vous pouvez réécrire votre IsVariant fonction à être beaucoup plus sympathique, par manuellement l'analyse de la vt membre de la Variant. Il sera très probablement avoir VT_BYREF drapeau et le drapeau quoi qu'il en fait des points d'. Mais afin de savoir si une variable a été déclarée dans le code As Range ou As Object, vous devez être le compilateur.
  • Ce qui explique beaucoup de lui. La fenêtre variables locales probablement obtient ses informations par une combinaison de l'analyse des Dim états et dynamiquement via la type fonction. Je me doutais bien qu'une certaine forme d'analyse est inévitable si je veux vraiment le type complet, mais a été en espérant que j'ai été donnant sur quelque chose (relativement) simple.
  • Je ne savais pas que vous pourriez explorer les types de variantes comme votre réponse à cette question. Merci pour ça. Si vous pourriez recueillir certains de vos commentaires dans une réponse, je vais l'accepter (ou au moins upvote si quelqu'un arrive avec une réponse plus complète).
  • Question intéressante, d'un couple de points: dans votre test() routine vous utilisez IsObject pas IsTypeObject, mais cela ne fonctionne toujours pas. Bizarrement, vous pouvez obtenir ce travail à l'intérieur d'une seule fonction, mais dès que vous passez la variable à une autre fonction (même si vous spécifiez ByRef) est obtient une hiérarchie de Variant\Object\Range comme indiqué par les habitants de la fenêtre elle-même. Bonne question mais, dommage, il semble que la réponse est non!
  • La solution peut impliquer l'accès à l'objet VBE modèle et l'analyse du code? Rubberduck le fait, analyse le projet dans son ensemble et résout les identifiants et leurs usages de tri et de détermine de quel type elles sont, mais ne pas essayer de déterminer le "type" d'une Variant - si nous avons légèrement modifié Rubberduck pour exposer une API COM que le code VBA peut utiliser pour "parcourir" ou "requête" une variable, la déclaration et les usages, je pense que vous pourriez avoir la dernière pièce de votre puzzle. FWIW, que de l'API COM est sur notre feuille de route. Bonne chance!
  • C'est une bonne idée, et il pourrait être nécessaire. C'est très probablement à ce que les habitants de la fenêtre de la réalité.
  • Pas de. Les habitants de la fenêtre a effectivement accès à la pile d'appel. Ne sorte de la fenêtre d'observation. Ne pas dire qu'il n'est pas possible, juste que c'est pas comment les habitants de la fenêtre fonctionne sous le capot.
  • Clairement, vous avez raison que la pile des appels est utilisé, mais je soupçonne qu'il y a probablement un élément de l'analyse ainsi.

InformationsquelleAutor John Coleman | 2015-11-26