确定变量的完整类型 [英] Determining the full type of a variable

查看:76
本文介绍了确定变量的完整类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过变量的完整类型,我的意思是您在即时窗口中获得的信息种类:

By the full type of a variable I mean the sort of information that you get in the immediate window:

我想使用VBA动态确定类型信息.函数TypeName()不执行我想要的操作,因为它返回变量的子类型,并且无法区分例如保存范围的变量,保存范围的对象变量和保存范围的范围变量.

I would like to determine the type information dynamically using VBA. The function TypeName() doesn't do what I want since it returns the subtype of a variant and doesn't distinguish between e.g. a variant variable holding a range, an object variable holding a range, and a range variable holding a range.

作为第一步,我编写了一个函数来检测是否将变体传递给它.它通过利用按引用传递语义来工作.该代码使用只能用变体完成的参数来执行操作,因此如果传递的变量实际上不是变体,则将触发错误:

As a preliminary step, I wrote a function which detects if a variant is passed to it. It works by exploiting pass-by-reference semantics. The code does things with its argument that can only be done with a variant and will thus trigger an error if the passed variable isn't actually a variant:

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

基于此,我写道:

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

测试代码:

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

输出:

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

这几乎是我想要的-但不能区分持有范围的对象变量和持有范围的范围变量.我试图编写一个名为IsTypeObject的函数,该函数与IsVariant相似,但似乎无法使其正常工作:

This is almost what I want -- but doesn't distinguish between an object variable holding a range and a range variable holding a range. I've tried to write a function called IsTypeObject which works similarly to IsVariant but can't seem to get it to work:

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

测试:

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

但是即使我认为使IsVariant起作用的相同的按引用语义也应该使IsTypeObject起作用(您不能将集合分配给范围),但这仍会打印True.我尝试了各种调整,但似乎无法区分通用对象变量和特定对象变量(例如范围变量).

But this prints True even though I would think that the same pass-by-reference semantics which makes IsVariant work should also make IsTypeObject work (you can't assign a collection to a range). I've tried various tweaks but can't seem to distinguish between the generic object variables and specific object variables such as range variables.

那么-关于如何动态获取变量的完整类型的任何想法吗? (动机是作为debug-log实用程序的一部分)

So -- any ideas for how to dynamically get the full type of a variable? (The motivation is as part of a debug-log utility)

推荐答案

是的,您可以这样做:它需要对指针有一点了解,并且需要'dereferencing'...

Yes, you can do this: it requires a little knowledge of pointers and the concept of 'dereferencing'...

这是执行此操作的代码:

 公共函数VariantTypeName(ByRef MyVariant)作为字符串
'返回变量的扩展类型名称,指示
'无论是简单的数据类型(例如:Long Integer)还是
'包含该类型数据的变体,例如:"Variant/Long" 
Dim iType作为整数 常量VT_BYREF =& H4000&
CopyMemory iType,MyVariant,2
'iType现在包含传入参数的VarType '与按位表示的VT_BYREF标志结合使用 通过参考传递.换句话说,它是一个指针, '不是变量(或其副本)的数据结构
'因此,我们应该拥有VT_BYREF-我们一直希望 '当MyVariant是变体时,因为变体是结构 '使用指向存储数据的一个或多个指针...
'但是,VBA实现的变体将始终 '取消引用指针-所有指针-传递给我们 '直接获取数据,剥离所有信息 '关于参考资料...
如果(iType和VT_BYREF)= VT_BYREF则 '按位算法检测VT_BYREF标志: VariantTypeName = TypeName(MyVariant) 别的 '没有VT_BYREF标志.这是一个变量,而不是变量: VariantTypeName ="Variant/"& TypeName(MyVariant) 如果结束
结束功能

Here's the code to do it:

Public Function VariantTypeName(ByRef MyVariant) As String
' Returns the expanded type name of a variable, indicating
' whether it's a simple data type (eg: Long Integer), or a
' Variant containing data of that type, eg: "Variant/Long"
Dim iType As Integer Const VT_BYREF = &H4000&
CopyMemory iType, MyVariant, 2
' iType now contains the VarType of the incoming parameter ' combined with a bitwise VT_BYREF flag indicating that it ' was passed by reference. In other words, it's a pointer, ' not the data structure of the variable (or a copy of it)
' So we should have VT_BYREF - and we'd always expect to ' when MyVariant is a Variant, as variants are a structure ' which uses a pointer (or pointers) to the stored data...
' However, the VBA implementation of a variant will always ' dereference the pointer - all the pointers - passing us ' straight to the data, stripping out all that information ' about references...
If (iType And VT_BYREF) = VT_BYREF Then ' Bitwise arithmetic detects the VT_BYREF flag: VariantTypeName = TypeName(MyVariant) Else ' No VT_BYREF flag. This is a Variant, not a variable: VariantTypeName = "Variant/" & TypeName(MyVariant) End If
End Function

(对 CopyMemory API函数的声明在下面几段之内).

(Declarations for the CopyMemory API function are a few paragraphs further down).

这需要一些解释,因为Visual Basic语言家族旨在保护您不受变量及其类型的实现细节(尤其是指针的概念)的影响,并且我的代码确实涉及一些横向思考.

That needs some explanation, because the Visual Basic family of languages are designed to shield you from the implementation details of variables and their types - and from the concept of pointers in particular - and my code does involve a bit of lateral thinking.

简单来说,您的变量有一个名称-您在代码中看到的类似'intX'的字符串;分配用于包含实际数据的内存区域;以及该内存的地址.

In simple terms, your variables have a name - a string like 'intX' you see in your code; an area of memory allocated to contain the actual data; and an address for that memory.

该地址实际上是分配给该变量的内存的开始,并且该变量将实现为内存中的结构,该结构由与实际数据的偏移量定义,大小为(或长度)-对于复杂类型,通过内存中其他结构的地址偏移量实现.这些大小和偏移量是预定义的:它们是变量的实际实现,而我们的VBA开发人员很少需要知道这一点-我们声明类型,并为我们完成所有工作.

That address will actually be for the start of the memory allocated to the variable, and the variable will be implemented as a structure in memory defined by offsets to the actual data, with the size (or length) of data - and, for complex types, by offsets to addresses to other structures in memory. Those sizes and offsets are predefined: they are the actual implementation of the variable, and we VBA developers rarely need to know about that - we declare the type, and its all done for us.

今天您需要知道的第一件事是VBA中变量地址的前两个字节为

The first thing that you need to know today is that the first two bytes at address of a variable in VBA are the enumerated var type: that's how the VarType() Function works.

程序通过该地址时,而不是通过复制内存中的数据分配,而是将该地址作为指针进行传递.是的,我有些简化了,但是VBA开发人员确实知道获取指针和数据副本之间的区别:它在 ByRef ByVal 标识符中声明函数时,我们使用传入参数.

When the program passes that address, instead of passing a copied allocation of the data in memory, it passes that address as a pointer. Yes, I'm oversimplifying some of this, but VBA developers do actually know the difference between getting a pointer and a copy of the data: it's in the ByRef and ByVal identifiers we use for incoming parameters when we declare a function.

VBA和VB非常擅长保护我们不受细节影响:太好了,以至于我们无法使用 VarType TypeName 来检测我们已经传递了一个值或对其的引用;甚至是对引用的引用,也就是对引用的引用.

VBA and VB are very, very good at shielding us from the details: so good, that we can't use VarType and TypeName to detect that we've been passed a value, or a reference to it; or even a reference to a reference, to a reference.

这很重要,因为变量是其他变量的包装,并且结构为您提供了指向它所包含的变量的指针,并使用var类型对其进行了描述:但是,我们无法知道VBA -我们直接沿地址所指示的行向下传递,一直到我们将要使用的数据,而VBA varType 从不告诉我们我们是通过以下方式间接到达那里的通过指针定义的连续地址进行几跳.

This matters, because a variant is a wrapper for other variables, and the structure gives you a pointer to the variable that it contains with the var type to describe it: however, we have no way of knowing that in VBA - we are passed straight down the line indicated by the address, all the way to the data we are going to use, and the VBA varType never tells us that we went there indirectly by several hops through successive addresses defined by pointers.

但是,如果您准备使用API​​调用查看指针后面的那两个字节,则该信息确实存在.

However, that information does exist, if you're prepared to look at those two bytes behind the pointer using an API call.

正如我所说,这两个字节包含var类型-但还有更多:它们包含var类型,并与按位标记 VT_BYREF 组合,指示这是对存储的引用或指针数据类型,而不是数据本身.因此,这段代码可以可靠地告诉您您的var类型,稍加思考,以便在我们不愿意的时候克服VBA的帮助:

As I said, those two bytes contain the var type - but there's more: they contain the var type combined with a bitwise marker VT_BYREF indicating that this is a reference, or pointer, to the stored data type, and not the data itself. So this code will reliably tell you your var type, with a little lateral thinking to get over VBA being helpful when we'd rather it wasn't:

 公共函数DereferencedType(ByRef MyVar)as Long 
将Dim iType转换为整数
常量VT_BYREF =& H4000&
'变量的前两个字节是带有ID的类型ID '如果我们将变量传递给,则按位或到VT_BYREF '参考...该功能的确切作用是:
CopyMemory iType,MyVar,2
DereferencedType = iType'Mod VT_BYREF
'如果需要,请使用"Mod VT_BYREF"分隔类型
结束功能

Public Function DereferencedType(ByRef MyVar) As Long
Dim iType As Integer
Const VT_BYREF = &H4000&
' The first two bytes of a variable are the type ID with a ' bitwise OR to VT_BYREF if we were passed the variable by ' reference... Which is exactly what this function does:
CopyMemory iType, MyVar, 2
DereferencedType = iType ' Mod VT_BYREF
'Use "Mod VT_BYREF" to separate out the type if you want
End Function

...这就是它的实际工作方式:向其传递一个简单的变量,它将告诉您通过引用传递了该变量:

  Dim str1作为字符串
str1 =一百"
Debug.Print字符串变量:"& DereferencedType(str1)
 

...And that's how it actually works: pass it a simple variable, and it'll tell you that you passed the variable by reference:

Dim str1 As String
str1 = "One Hundred"
Debug.Print "String Variable: " & DereferencedType(str1)

 字符串变量:16392
 

String Variable: 16392

但是,如果您将字符串变量传递给我们的函数,则VBA的Variant实现将使您免于涉及指针和按引用传递的所有复杂性-一直到数据-并为您提供您的数据中去除了所有不必要的信息:

 将varX作为变体
varX =一百"
Debug.Print"String Variant:"& DereferencedType(varX)
 

But if you pass our function a string variant, VBA's implementation of the Variant will shield you from all that complexity about pointers and passing by reference - all the way down to the data - and give you your data with all that unwanted information stripped out:

Dim varX As Variant
varX = "One Hundred"
Debug.Print "String Variant:  " & DereferencedType(varX)

 字符串变体:8
 

String Variant:  8

我将留给您使用 VT_BYREF 对返回值进行OR或NOT运算的代码,为您提供Variant/String和变体/长输出.

I'll leave you to code up an OR or NOT operation on the returned values with VT_BYREF, to give you the 'Variant/' label for your expanded string descriptors of the Variant/String and Variant/Long outputs.

我建议您如图所示声明CopyMemory API调用,并针对可能遇到的所有环境使用条件编译器常量:

 
#如果使用VBA7和Win64,则在64位Windows下使用64位Excel
                           '使用LongLong和LongPtr 
私有声明PtrSafe子CopyMemory库"kernel32"别名"RtlMoveMemory" _ (目的地为_ 来源,_ ByVal Length As LongLong)
# ElseIf VBA7然后在所有环境中使用64位Excel '仅使用LongPtr,LongLong不可用
私有声明PtrSafe子CopyMemory库"kernel32"别名"RtlMoveMemory" _ (目的地为_ 来源,_ ByVal长度一样长)
#其他'32位Excel
私有声明子CopyMemory库"kernel32"别名"RtlMoveMemory" _ (目的地为_ 来源,_ ByVal长度一样长) #如果结束

I recommend that you declare the CopyMemory API call as shown, with conditional compiler constants for all the environments you're likely to encounter:


#If VBA7 And Win64 Then    ' 64 bit Excel under 64-bit Windows
                           ' Use LongLong and LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As LongLong)
#ElseIf VBA7 Then ' 64 bit Excel in all environments ' Use LongPtr only, LongLong is not available
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long)
#Else ' 32 bit Excel
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long) #End If

与此同时,更棘手的问题-获取Variant/Object/Range-将需要进一步的工作.我可以告诉您,您的变体包含一个范围,并且我可以说它是一个变体,而不是它本身是一个范围:但是,我现在无法沿着声明的链条来揭示一个对象被声明为对象"指向一个范围:

Meanwhile, the harder question - getting Variant/Object/Range - will need further work. I can tell you that your variant contains a range, and I can tell that it's a variant and not itself a range: but I can't go down the chain of declarations to reveal that an object was declared as 'object' now that it points to a range:

VarX设置为等于范围对象变量:
    varX:type = 8204范围解除引用的类型= 9
    rng1:类型= 8204范围已取消引用类型= 16393 
VarX设置为等于范围对象的值,即二维数组: varX:type = 8204 Variant()取消引用的Type = 8204 arr1:类型= 8204 Variant()取消引用类型= 8204
数组变量被擦除为Empty().检查varX: varX:type = 8204 Variant()取消引用的Type = 8204 arr1:类型= 8204 Variant()取消引用类型= 8204
VarX设置为等于对象"变量,该变量已设置为一个范围: varX:type = 8204范围解除引用的类型= 9 obj1:类型= 8204范围已解除引用类型= 16393

VarX is set equal to a range object variable:
    varX: type=8204     Range   Dereferenced Type=9
    rng1: type=8204     Range   Dereferenced Type=16393
VarX is set equal to a range object's value, a 2-dimensional array: varX: type=8204 Variant() Dereferenced Type=8204 arr1: type=8204 Variant() Dereferenced Type=8204
The array variable is erased to Empty(). Inspect varX: varX: type=8204 Variant() Dereferenced Type=8204 arr1: type=8204 Variant() Dereferenced Type=8204
VarX is set equal to an 'object' variable, which has been set to a range: varX: type=8204 Range Dereferenced Type=9 obj1: type=8204 Range Dereferenced Type=16393

这是生成该代码的代码,以及完整的输出:

Here's the code that generated that, and the full output:

 
Public Sub TestVar()
Dim varX作为变体 昏暗的str1作为字符串 昏暗的lng1 Dim rng1作为Excel.Range Dim arr1作为变体 昏暗的obj1作为对象
Debug.Print未初始化:" 调试打印 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "str1:type ="& VarType(str1)& vbTab& vbTab& TypeName(str1)& vbTab& 取消引用的类型="& DereferencedType(str1) 调试打印vbTab& "lng1:type ="& VarType(lng1)& vbTab& vbTab& TypeName(lng1)& vbTab& 取消引用的类型="& DereferencedType(lng1) Debug.Print
varX =一百" str1 =一百" lng1 = 100 Debug.Print"varX和str1填充相同的文字:" 调试打印 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "str1:type ="& VarType(str1)& vbTab& vbTab& TypeName(str1)& vbTab& 取消引用的类型="& DereferencedType(str1) 调试打印vbTab& "lng1:type ="& VarType(lng1)& vbTab& vbTab& TypeName(lng1)& vbTab& 取消引用的类型="& DereferencedType(lng1) Debug.Print
varX = 100 lng1 = 100 Debug.Print"varX和lng1用相同的整数填充:" 调试打印 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "str1:type ="& VarType(str1)& vbTab& vbTab& TypeName(str1)& vbTab& 取消引用的类型="& DereferencedType(str1) 调试打印vbTab& "lng1:type ="& VarType(lng1)& vbTab& vbTab& TypeName(lng1)& vbTab& 取消引用的类型="& DereferencedType(lng1) Debug.Print
varX = str1 Debug.Print"VarX设置为等于str1:" 调试打印 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "str1:type ="& VarType(str1)& vbTab& vbTab& TypeName(str1)& vbTab& 取消引用的类型="& DereferencedType(str1) Debug.Print
varX = lng1 Debug.Print"VarX设置为等于lng1:" 调试打印 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "lng1:type ="& VarType(lng1)& vbTab& vbTab& TypeName(lng1)& vbTab& 取消引用的类型="& DereferencedType(lng1) Debug.Print
设置varX = ActiveSheet.Range("A1:C3") Debug.Print"VarX设置为等于范围:" 调试打印 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) Debug.Print
设置rng1 = ActiveSheet.Range("A1:C3") 设置varX = Nothing 设置varX = rng1 Debug.Print"VarX设置为等于范围对象变量:" 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "rng1:type ="& VarType(rng1)& vbTab& vbTab& TypeName(rng1)& vbTab& 取消引用的类型="& DereferencedType(rng1) Debug.Print
arr1 = rng1.Value2 设置varX = Nothing varX = arr1 Debug.Print"VarX设置为等于范围对象的值,即二维数组:" 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "arr1:type ="& VarType(rng1)& vbTab& vbTab& TypeName(arr1)& vbTab& 取消引用的类型="& DereferencedType(arr1) Debug.Print
删除arr1 Debug.Print将数组变量擦除为Empty().检查varX:" 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "arr1:type ="& VarType(rng1)& vbTab& vbTab& TypeName(arr1)& vbTab& 取消引用的类型="& DereferencedType(arr1) Debug.Print
设置obj1 = ActiveSheet.Range("A1:C3") 设置varX = Nothing 设置varX = obj1 Debug.Print"VarX设置为等于'object'变量,该变量已设置为一个范围:" 调试打印vbTab& "varX:type ="& VarType(varX)& vbTab& vbTab& TypeName(varX)& vbTab& 取消引用的类型="& DereferencedType(varX) 调试打印vbTab& "obj1:type ="& VarType(rng1)& vbTab& vbTab& TypeName(obj1)& vbTab& 取消引用的类型="& DereferencedType(obj1) Debug.Print
结束子


Public Sub TestVar()
Dim varX As Variant Dim str1 As String Dim lng1 As Long Dim rng1 As Excel.Range Dim arr1 As Variant Dim obj1 As Object
Debug.Print "Uninitialised:" Debug.Print Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "str1: type=" & VarType(str1) & vbTab & vbTab & TypeName(str1) & vbTab & "Dereferenced Type=" & DereferencedType(str1) Debug.Print vbTab & "lng1: type=" & VarType(lng1) & vbTab & vbTab & TypeName(lng1) & vbTab & "Dereferenced Type=" & DereferencedType(lng1) Debug.Print
varX = "One Hundred" str1 = "One Hundred" lng1 = 100 Debug.Print "varX and str1 are populated with the same literal:" Debug.Print Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "str1: type=" & VarType(str1) & vbTab & vbTab & TypeName(str1) & vbTab & "Dereferenced Type=" & DereferencedType(str1) Debug.Print vbTab & "lng1: type=" & VarType(lng1) & vbTab & vbTab & TypeName(lng1) & vbTab & "Dereferenced Type=" & DereferencedType(lng1) Debug.Print
varX = 100 lng1 = 100 Debug.Print "varX and lng1 are populated with the same integer:" Debug.Print Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "str1: type=" & VarType(str1) & vbTab & vbTab & TypeName(str1) & vbTab & "Dereferenced Type=" & DereferencedType(str1) Debug.Print vbTab & "lng1: type=" & VarType(lng1) & vbTab & vbTab & TypeName(lng1) & vbTab & "Dereferenced Type=" & DereferencedType(lng1) Debug.Print
varX = str1 Debug.Print "VarX is set equal to str1:" Debug.Print Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "str1: type=" & VarType(str1) & vbTab & vbTab & TypeName(str1) & vbTab & "Dereferenced Type=" & DereferencedType(str1) Debug.Print
varX = lng1 Debug.Print "VarX is set equal to lng1:" Debug.Print Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "lng1: type=" & VarType(lng1) & vbTab & vbTab & TypeName(lng1) & vbTab & "Dereferenced Type=" & DereferencedType(lng1) Debug.Print
Set varX = ActiveSheet.Range("A1:C3") Debug.Print "VarX is set equal to a range:" Debug.Print Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print
Set rng1 = ActiveSheet.Range("A1:C3") Set varX = Nothing Set varX = rng1 Debug.Print "VarX is set equal to a range object variable:" Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "rng1: type=" & VarType(rng1) & vbTab & vbTab & TypeName(rng1) & vbTab & "Dereferenced Type=" & DereferencedType(rng1) Debug.Print
arr1 = rng1.Value2 Set varX = Nothing varX = arr1 Debug.Print "VarX is set equal to a range object's value, a 2-dimensional array:" Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "arr1: type=" & VarType(rng1) & vbTab & vbTab & TypeName(arr1) & vbTab & "Dereferenced Type=" & DereferencedType(arr1) Debug.Print
Erase arr1 Debug.Print "The array variable is erased to Empty(). Inspect varX:" Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "arr1: type=" & VarType(rng1) & vbTab & vbTab & TypeName(arr1) & vbTab & "Dereferenced Type=" & DereferencedType(arr1) Debug.Print
Set obj1 = ActiveSheet.Range("A1:C3") Set varX = Nothing Set varX = obj1 Debug.Print "VarX is set equal to an 'object' variable, which has been set to a range:" Debug.Print vbTab & "varX: type=" & VarType(varX) & vbTab & vbTab & TypeName(varX) & vbTab & "Dereferenced Type=" & DereferencedType(varX) Debug.Print vbTab & "obj1: type=" & VarType(rng1) & vbTab & vbTab & TypeName(obj1) & vbTab & "Dereferenced Type=" & DereferencedType(obj1) Debug.Print
End Sub

结果:

未初始化:
    varX:type = 0空的解除引用的Type = 0
    str1:类型= 8字符串已取消引用类型= 16392
    lng1:类型= 3长引用类型= 16387 
varX和str1用相同的文字填充: varX:type = 8字符串解引用的Type = 8 str1:type = 8字符串取消引用的类型= 16392 lng1:类型= 3长引用类型= 16387
varX和lng1用相同的整数填充: varX:type = 2整数解引用的Type = 2 str1:type = 8字符串取消引用的类型= 16392 lng1:类型= 3长引用类型= 16387
VarX设置为等于str1: varX:type = 8字符串解引用的Type = 8 str1:类型= 8字符串已取消引用类型= 16392
VarX设置为等于lng1: varX:type = 3长引用类型= 3 lng1:类型= 3长引用类型= 16387
VarX设置为等于范围: varX:type = 8204范围取消引用的类型= 9
VarX设置为等于范围对象变量: varX:type = 8204范围解除引用的类型= 9 rng1:类型= 8204范围已取消引用类型= 16393
VarX设置为等于范围对象的值,即二维数组: varX:type = 8204 Variant()取消引用的Type = 8204 arr1:类型= 8204 Variant()取消引用类型= 8204
数组变量被擦除为Empty().检查varX: varX:type = 8204 Variant()取消引用的Type = 8204 arr1:类型= 8204 Variant()取消引用类型= 8204
VarX设置为等于对象"变量,该变量已设置为一个范围: varX:type = 8204范围解除引用的类型= 9 obj1:类型= 8204范围已解除引用类型= 16393

Uninitialised:
    varX: type=0        Empty   Dereferenced Type=0
    str1: type=8        String  Dereferenced Type=16392
    lng1: type=3        Long    Dereferenced Type=16387
varX and str1 are populated with the same literal: varX: type=8 String Dereferenced Type=8 str1: type=8 String Dereferenced Type=16392 lng1: type=3 Long Dereferenced Type=16387
varX and lng1 are populated with the same integer: varX: type=2 Integer Dereferenced Type=2 str1: type=8 String Dereferenced Type=16392 lng1: type=3 Long Dereferenced Type=16387
VarX is set equal to str1: varX: type=8 String Dereferenced Type=8 str1: type=8 String Dereferenced Type=16392
VarX is set equal to lng1: varX: type=3 Long Dereferenced Type=3 lng1: type=3 Long Dereferenced Type=16387
VarX is set equal to a range: varX: type=8204 Range Dereferenced Type=9
VarX is set equal to a range object variable: varX: type=8204 Range Dereferenced Type=9 rng1: type=8204 Range Dereferenced Type=16393
VarX is set equal to a range object's value, a 2-dimensional array: varX: type=8204 Variant() Dereferenced Type=8204 arr1: type=8204 Variant() Dereferenced Type=8204
The array variable is erased to Empty(). Inspect varX: varX: type=8204 Variant() Dereferenced Type=8204 arr1: type=8204 Variant() Dereferenced Type=8204
VarX is set equal to an 'object' variable, which has been set to a range: varX: type=8204 Range Dereferenced Type=9 obj1: type=8204 Range Dereferenced Type=16393

总而言之,这是一个有趣的问题:我的回答的简短版本是,您可以消除变体和简单类型的歧义,但是声明为对象"的对象不适合该分析.

All in all, an interesting question: the short version of my answer is that you can disambiguate variants and simple types, but an an object declared as 'object' isn't amenable to that analysis.

这篇关于确定变量的完整类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆