【问题标题】:Is there a way to count elements in a VBA enum?有没有办法计算 VBA 枚举中的元素?
【发布时间】:2013-04-24 13:35:43
【问题描述】:

是否有适当的方法来计算 VBA 中枚举的元素? 目前,我在下面的示例中留下了一个枚举值,例如KeepThisOneHere

Enum TestEnum
   ValueA
   ValueB
   ValueC
   KeepThisOneHere
End Enum

我使用最后一个值来知道大小...我不喜欢这个解决方案,因为我不确定我是否保证这些值将始终以相同的方式被索引,并且代码可能会被更改可能会在最后一个特殊值之后添加值的第三方,默默地破坏其余代码。

【问题讨论】:

    标签: excel vba enums


    【解决方案1】:

    不确定这里的礼仪,所以我会发布它,如果有建议,我会回来删除它。 Chip Pearson 在 Code Cage 论坛 (http://www.thecodecage.com/forumz/microsoft-excel-forum/170961-loop-enumeration-constants.html) 上发布了此代码。我的机器上没有 TypeLinInfo DLL,所以我无法测试它(我相信谷歌会找到下载 TLBINF32.dll 的地方)。尽管如此,这是他的整个帖子,以防止其他人注册论坛:

    只有在您的计算机上安装了 TypeLibInfo DLL 时才能执行此操作 电脑。在 VBA 中,转到“工具”菜单,选择“引用”,然后滚动 向下到“TypeLib 信息”。如果该项目存在,请检查它。如果没有 存在,然后放弃阅读,因为你不能做你想做的事。这 您需要的 DLL 文件名为 TLBINF32.dll。

    以下代码展示了如何获取 XLYesNoGuess 枚举:

    Sub AAA()
        Dim TLIApp As TLI.TLIApplication
        Dim TLILibInfo As TLI.TypeLibInfo
        Dim MemInfo As TLI.MemberInfo
        Dim N As Long
        Dim S As String
        Dim ConstName As String
    
        Set TLIApp = New TLI.TLIApplication
        Set TLILibInfo = New TLI.TypeLibInfo
        Set TLILibInfo = TLIApp.TypeLibInfoFromFile( _
            ThisWorkbook.VBProject.References("EXCEL").FullPath)
    
        ConstName = "XLYesNoGuess"
        For Each MemInfo In _
            TLILibInfo.Constants.NamedItem(ConstName).Members
            S = MemInfo.Name
            N = MemInfo.Value
            Debug.Print S, CStr(N)
        Next MemInfo
    End Sub
    

    利用这些知识,您可以创建两个有用的功能。枚举名称 返回一个字符串数组,其中包含一个值的名称 枚举:

    Function EnumNames(EnumGroupName As String) As String()
        Dim TLIApp As TLI.TLIApplication
        Dim TLILibInfo As TLI.TypeLibInfo
        Dim MemInfo As TLI.MemberInfo
        Dim Arr() As String
        Dim Ndx As Long
        Set TLIApp = New TLI.TLIApplication
        Set TLILibInfo = New TLI.TypeLibInfo
        Set TLILibInfo = TLIApp.TypeLibInfoFromFile( _
            ThisWorkbook.VBProject.References("EXCEL").FullPath)
        On Error Resume Next
        With TLILibInfo.Constants.NamedItem(EnumGroupName)
            ReDim Arr(1 To .Members.Count)
            For Each MemInfo In .Members
                Ndx = Ndx + 1
                Arr(Ndx) = MemInfo.Name
            Next MemInfo
        End With
    
        EnumNames = Arr
    End Function
    

    您可以使用以下代码调用此函数:

    Sub ZZZ()
        Dim Arr() As String
        Dim N As Long
        Arr = EnumNames("XLYesNoGuess")
        For N = LBound(Arr) To UBound(Arr)
            Debug.Print Arr(N)
        Next N
    End Sub
    

    您还可以创建一个函数来测试是否为 枚举:

    Function IsValidValue(EnumGroupName As String, Value As Long) As
        Boolean
        Dim TLIApp As TLI.TLIApplication
        Dim TLILibInfo As TLI.TypeLibInfo
        Dim MemInfo As TLI.MemberInfo
        Dim Ndx As Long
        Set TLIApp = New TLI.TLIApplication
        Set TLILibInfo = New TLI.TypeLibInfo
        Set TLILibInfo = TLIApp.TypeLibInfoFromFile( _
            ThisWorkbook.VBProject.References("EXCEL").FullPath)
        On Error Resume Next
        With TLILibInfo.Constants.NamedItem(EnumGroupName)
            For Ndx = 1 To .Members.Count
                If .Members(Ndx).Value = Value Then
                    IsValidValue = True
                    Exit Function
                End If
            Next Ndx
        End With
        IsValidValue = False
    End Function
    

    如果为 EnumGroupName 定义了 Value 或 如果未定义,则为 False。你可以用代码调用这个函数 像下面这样:

    Sub ABC()
        Dim B As Boolean
        B = IsValidValue("XLYesNoGuess", xlYes)
        Debug.Print B ' True for xlYes
        B = IsValidValue("XLYesNoGuess", 12345)
        Debug.Print B ' False for 12345
    End Sub
    

    谨此, 奇普·皮尔逊 微软 MVP 1998 - 2010 培生软件咨询有限责任公司 www.cpearson.com [网站上的电子邮件]

    【讨论】:

    • 在我看来这是为了从 Excel 类型信息中提取数据,这适用于 Excel 类型,但不适用于用户定义的类型。
    • tlbinf32.dll 不是 TLI.TLIApplication 的唯一来源。如果你有 Visual Studio,它带有 vstlbinf.dll 但这需要手动注册。我在 64 位 Windows 8.1 上运行 VS 2012,并通过从以管理员身份启动的 cmd 提示符运行这些命令来实现此功能: cd C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE regsvr32 vstlbinf.dll即使在那时,该脚本对我来说也不是“本机”工作,但如果我从 32 位 cmd 窗口运行 cscript 命令,您可以使用 C:\Windows\SysWOW64\cmd.exe 开始
    • 这一行:Set TLILibInfo = New TLI.TypeLibInfo 是多余的。每次使用它时,都会在下一行分配一个全新的对象。
    【解决方案2】:

    这是我的解决方法的一个示例,非常简单:

    Enum FileSpecFields
        FileSpecFields_Start                    '(zero-based)
            FileNameIdx = FileSpecFields_Start
            FolderNameIdx
            BasePathIdx
            FullPathIdx
            CopyStatus
        FileSpecFields_End = CopyStatus
    End Enum
    
    '...
    
    ReDim FileSpecList(1 To MaxFiles, FileSpecFields_Start To FileSpecFields_End) As String
    
    '...
    

    但请注意,如果您使用的是基于 1 的枚举,则可能需要调整 _End 值定义,具体取决于您使用它的方式。此外,对于从零开始的枚举,_End 值与其项目数不同。而且,如果您在最后添加项目,则必须相应地更新 _End 值的定义。最后,如果你的枚举是一个不连续的值范围,那么所有的赌注都用这种方法!

    【讨论】:

    • 一个建议 - 我做的事情和你一样,但我实际上将第一个和最后一个枚举命名为 [_First][_Last]。 VBA 在智能感知下拉列表中隐藏以下划线开头的枚举,因此您不必正常查看它们,但您仍然可以通过 FileSpecFields.[_First] 引用它们。
    • 很好的解决方案!但我不明白为什么有必要标记第一个枚举。只需标记最后一个:Enum MyEnum myItem1 myItem2 myItem3 myLast End Enum。然后用myLast - 1 获取枚举数。假设从 0 开始,默认情况下是哪个枚举。
    【解决方案3】:

    没有办法获得计数。

    你需要做的是循环遍历 Enum 的元素,直到你到达最后一个。

    Chip Pearson 有一些关于枚举常量的好技巧:Chip Pearson: Enum Variable Type

    【讨论】:

      【解决方案4】:

      如果您在设计时知道枚举类型,您可以将它们转换为 Static Property Get MyEnumColl() as Collection ...(不需要类,在第一次访问时静态初始化)从而轻松地遍历它们或像here所示那样计算它们

      【讨论】:

        【解决方案5】:
        Sub count()
            Dim n, c
        
            For n = headers.frstItem To headers.lastItem
                c = c + 1
            Next
            Debug.Print c
        End Sub
        

        【讨论】:

        • A.k.a.headers.lastItem - headers.frstItem + 1。仅当枚举值是连续的且按递增顺序时才有效。
        猜你喜欢
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 2013-10-27
        • 1970-01-01
        • 2016-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多