You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过集合、延迟绑定字典等方式关联多个VBA对象实例

高效关联共享唯一标识符的VBA对象实例方案

嘿,你这个场景用Scripting.Dictionary来处理就完美了——既能避免嵌套循环带来的性能损耗,又能轻松把共享唯一ID的对象关联起来。下面是具体的实现步骤和代码调整建议:

1. 先完善类模块的标识符属性

首先确保你的类(比如something类)能正确存储和暴露那个唯一标识符。假设你的唯一标识符存放在数据的第N列,补充类代码如下:

' class derived from Solution interface
Option Explicit
Implements Solution
Private amount_ As Integer
Private amountRef_ As String
Private linekey_ As String ' 新增:存储唯一标识符

Private Sub Class_Initialize()
End Sub

Public Sub Init(rng As Range)
    amount_ = rng.Cells(1, 1)
    amountRef_ = "'" & rng.Parent.Name & "'!" & rng.Columns.Item(1).Address
    linekey_ = rng.Cells(1, [替换为实际列号]) ' 读取唯一标识符,比如第10列就写10
End Sub

' 新增:暴露唯一标识符的只读属性
Public Property Get linekey() As String
    linekey = linekey_
End Property

' 原有的其他方法和属性保持不变...
Public Sub PrintOut()
    Debug.Print amount_, TypeName(Me), linekey_ & vbNewLine;
    Debug.Print amountRef_, TypeName(Me), linekeyRef_ & vbNewLine;
End Sub

Private Sub Class_Terminate()
    ' Debug.Print "WAN class instance deleted"
End Sub

Public Property Get amount() As Integer
    amount = amount_
End Property

Public Property Let amount(ByVal Value As Integer)
    amount_ = Value ' 这里原代码有问题,修正为给私有变量赋值
End Property

Public Property Get linekeyRef() As String
    linekeyRef = linekeyRef_
End Property

Public Property Let linekeyRef(ByVal Value As String)
    linekeyRef_ = Value ' 原代码有问题,修正为给私有变量赋值
End Property

' Implement required interface properties
Private Property Get Solution_address() As String
    Solution_address = amountRef_ ' 原代码的address未定义,修正为对应属性
End Property

2. 修改读取数据的逻辑,用字典分组

我们在ReadData过程中新增一个Dictionary参数,用来按唯一标识符分组所有对象,字典的键是唯一ID,值是对应ID下的所有对象集合:

Option Explicit
Sub ReadData(Solutions As Collection, ByRef solutionGroups As Dictionary)
    Set Solutions = New Collection
    Set solutionGroups = New Dictionary ' 初始化分组字典
    Dim Solution As Variant
    Dim ws As Worksheet
    Dim rng As Range
    Dim rowamount As Long
    rowamount = Worksheets("source").Range("Named_ranges").Rows.Count
    Dim myrow As Integer
    Dim suspectWorksheet As String
    Dim TargetWorksheet As Worksheet
    Dim TargetWorkRange As String
    Dim TargetRangeCount As Integer
    Dim x As Integer
    Dim groupKey As String
    
    For myrow = 1 To rowamount
        suspectWorksheet = Worksheets("source").Range("Named_ranges").Cells(myrow, 1)
        Set TargetWorksheet = Worksheets(suspectWorksheet)
        If TargetWorksheet.Visible = True Then
            TargetWorkRange = Worksheets("source").Range("Named_ranges").Cells(myrow, 2)
            TargetRangeCount = Worksheets("source").Range("Named_ranges").Cells(myrow, 3)
            For x = 1 To TargetRangeCount
                Debug.Print "Loop " & x
                If Worksheets(suspectWorksheet).Range(TargetWorkRange).Cells(x + 1, 1) > 0 Then
                    Set rng = Worksheets(suspectWorksheet).Range(TargetWorkRange).Resize(1, 60).Offset(x, 0)
                    Set Solution = solutionClassFactory(rng)
                    Solutions.Add Solution
                    
                    ' 核心:按唯一标识符分组
                    groupKey = Solution.linekey
                    If Not solutionGroups.Exists(groupKey) Then
                        ' 若该ID首次出现,创建新集合存储对应对象
                        solutionGroups.Add groupKey, New Collection
                    End If
                    solutionGroups(groupKey).Add Solution
                End If
            Next x
        End If
    Next myrow
    Set TargetWorksheet = Nothing
End Sub

' Checks the type of solution and returns into a class
Function solutionClassFactory(rng As Range) As Variant
    Dim solutionType As String
    solutionType = rng.Cells(1, 51)
    Dim Solution As Variant
    Select Case solutionType
        Case "something": Set Solution = New something
    End Select
    Solution.Init rng
    Set solutionClassFactory = Solution
End Function

3. 后续处理关联对象

Create过程中,你可以直接通过分组字典快速获取同一ID下的所有对象,进行特殊处理:

Sub Create()
    Dim Solution As Variant
    Dim Solutions As Collection
    Dim solutionGroups As Dictionary ' 新增分组字典变量
    Dim TargetWorksheet As String
    Dim i As Integer
    Dim groupKey As Variant
    Dim groupItems As Collection
    Dim groupedSolution As Variant
    
    TargetWorksheet = "sheet"
    ReadData Solutions, solutionGroups ' 传入字典获取分组结果
    
    ' 第一步:先处理基础列输出(原逻辑)
    i = 5
    For Each Solution In Solutions
        Worksheets(TargetWorksheet).Cells(i, 1) = Solution.amount
        ' 其他基础列的输出逻辑...
        i = i + 1
    Next Solution
    
    ' 第二步:处理关联对象的特殊列输出
    i = 5 ' 回到起始行,根据实际需求调整
    For Each groupKey In solutionGroups.Keys
        Set groupItems = solutionGroups(groupKey)
        ' 如果组内有多个对象,说明需要关联处理
        If groupItems.Count > 1 Then
            For Each groupedSolution In groupItems
                ' 示例:将组内第一个对象的amount写入当前行的第2列
                Worksheets(TargetWorksheet).Cells(i, 2) = groupItems(1).amount
                i = i + 1
            Next groupedSolution
        Else
            ' 单个对象的情况,设置默认值或跳过
            Worksheets(TargetWorksheet).Cells(i, 2) = "无关联"
            i = i + 1
        End If
    Next groupKey
End Sub

注意事项

  • 前期绑定字典:需要在VBA编辑器中,点击工具->引用,勾选Microsoft Scripting Runtime,这样能获得智能提示。
  • 后期绑定字典:如果不想添加引用,可把Dim solutionGroups As Dictionary改成Dim solutionGroups As Object,初始化时写Set solutionGroups = CreateObject("Scripting.Dictionary"),缺点是没有智能提示。
  • 类型一致性:确保唯一标识符的类型统一(比如都是字符串或数字),避免字典键匹配出错。

内容的提问来源于stack exchange,提问作者MisterMe

火山引擎 最新活动