Vba 只有在公共对象模块中定义的用户定义类型才能强制到变量或从变量强制到变量,或传递到后期绑定函数

Vba 只有在公共对象模块中定义的用户定义类型才能强制到变量或从变量强制到变量,或传递到后期绑定函数,vba,excel,compiler-errors,Vba,Excel,Compiler Errors,我试图创建一个结构,我可以使用它来分离记录的各个元素,以便使用它们的组件。每个记录由记录编号、组、分区、类别和5个整数代码组成,这些代码将根据其组、分区和类别用于各种操作。每当我试图将记录类型传递到我的ArrayList时,我都会得到这个问题标题中所述的错误。我试着研究其他有这个错误的问题,但没有一个答案是有效的。我曾尝试为RecordType创建一个单独的类,但它说不能使用公共类类型。以下是我试图分离和使用的数据: 65f8|gh|l1|9k|985|8437|7894|9495|3730|

我试图创建一个结构,我可以使用它来分离记录的各个元素,以便使用它们的组件。每个记录由记录编号、组、分区、类别和5个整数代码组成,这些代码将根据其组、分区和类别用于各种操作。每当我试图将记录类型传递到我的ArrayList时,我都会得到这个问题标题中所述的错误。我试着研究其他有这个错误的问题,但没有一个答案是有效的。我曾尝试为RecordType创建一个单独的类,但它说不能使用公共类类型。以下是我试图分离和使用的数据:

65f8|gh|l1|9k|985|8437|7894|9495|3730|
4287|gh|w1|uk|7341|5638|7715|8906|698|
3s89|jk|w1|h7|225|487|2013|4328|4066|
62l5|lo|r5|9k|5103|9879|3448|2921|7581|
486p|lo|r5|uk|6882|9879|2672|1015|3160|
a597|lo|r6|m9|385|6915|3615|9195|9817|
1m36|hu|k8|h7|656|8064|3852|9110|9858|
这就是我写的代码。这些注释是我用来在excel中测试代码某些部分的循环

Type RecordType
    number As String
    group As String
    div As String
    cat As String
    code1 As Integer
    code2 As Integer
    code3 As Integer
    code4 As Integer
    code5 As Integer
End Type

Sub ProgramOne()


Dim fileName As String, textData As String, fileLine As String, rowList() As String, numOfRecords As Integer, someString As String
Dim rowNum As Integer, colNum As Integer, counter As Integer, counter2 As Integer, groupCount As Integer, divCount As Integer, catCount As Integer
Dim groupBool As Boolean, catBool As Boolean, divBool As Boolean, groupList As Object, divList As Object, catList As Object

Set groupList = CreateObject("System.Collections.ArrayList")
Set divList = CreateObject("System.Collections.ArrayList")
Set catList = CreateObject("System.Collections.ArrayList")

fileName = "/Users/Ricky/Desktop/project1Data.txt"
Open fileName For Input As #1
rowNum = 1

Dim records As Object
Set records = CreateObject("System.Collections.ArrayList")
Dim placeholder As RecordType

Do Until EOF(1)
    numOfRecords = numOfRecords + 1
    Line Input #1, fileLine
    rowList = Split(fileLine, "|")

    placeholder.number = rowList(0)
    placeholder.group = rowList(1)
    placeholder.div = rowList(2)
    placeholder.cat = rowList(3)
    placeholder.code1 = rowList(4)
    placeholder.code2 = rowList(5)
    placeholder.code3 = rowList(6)
    placeholder.code4 = rowList(7)
    placeholder.code5 = rowList(8)

    records.Add (placeholder)
Loop

'Dim counter2 As Integer
'counter2 = 2
'    For x = 0 To UBound(records) - LBound(records)
'        Cells(counter2, 1) = records(x).group
'        Cells(counter2, 2) = records(x).div
'        counter2 = counter2 + 1
'    Next

Close #1

'For x = 0 To UBound(records) - LBound(records)

    divBool = False
    catBool = False

groupCount = 0
divCount = 0
catCount = 0
'Dim GroupName As Variant

'For Each GroupName In groupList
'    groupBool = False
'    For num = 0 To UBound(records) - LBound(records)
'        If CStr(records(num).group) = CStr(GroupName) Then
'            groupBool = True
'        End If
'        If Not groupBool Then
'            groupCount = groupCount + 1
'            groupList(groupCount) = records(num).group
'        End If
'    Next num
'Next GroupName
counter = 0
counter2 = 0
For Each GroupName In records
    For Each GroupName2 In groupList
        If records(counter).group = groupList(counter2) Then
            groupBool = True
        End If
        counter2 = counter2 + 1
    Next GroupName2
    If groupBool = False Then

Next GroupName

Cells(1, 1) = "Number of records: " & numOfRecords
Cells(1, 2) = "Number of Groups: " & groupCount
Cells(2, 1) = "records index: " & UBound(records) - LBound(records)
counter = 0
'For Each GroupName In groupList
'    Cells(3, counter) = GroupName
'    counter = counter + 1
'Next GroupName
End Sub

添加一个新的类模块,将其称为
记录
,将您的
类型
移动到其中,使其成为
私有
,然后声明该类型的私有字段,并为每个成员公开一个
属性Get
和一个
属性Let

Option Explicit

Private Type TRecord
    Number As String
    Group As String
    Division As String
    Category As String
    Codes(1 To 5) As Long
End Type

Private this As TRecord

Public Property Get Number() As String
    Number = this.Number
End Property

Public Property Let Number(ByVal value As String)
    this.Number = value
End Property

Public Property Get Group() As String
    Group = this.Group
End Property

Public Property Let Group(ByVal value As String)
    this.Group = value
End Property

Public Property Get Division() As String
    Division = this.Division
End Property

Public Property Let Division(ByVal value As String)
    this.Division = value
End Property

Public Property Get Category() As String
    Category = this.Category
End Property

Public Property Let Category(ByVal value As String)
    this.Category = value
End Property

Public Property Get Code(ByVal index As Long) As Long
    Code = this.Codes(index)
End Property

Public Property Let Code(ByVal index As Long, ByVal value As Long)
    this.Codes(index) = value
End Property
现在改用该类的实例,它应该可以正常工作

要获得额外的酷系数,请删除并导出类模块,在记事本中打开它,并将其
VB\u PredeclaredId
属性设置为
True
。保存并重新导入模块:现在您的类有了一个默认实例,您可以使用该实例创建一个factory方法:

现在,读卡器循环可以如下所示:

Do Until EOF(1)
    numOfRecords = numOfRecords + 1
    Line Input #1, fileLine
    rowList = Split(fileLine, "|")
    records.Add Record.Create(rowList(0), rowList(1), rowList(2), rowList(3), rowList(4), rowList(5), rowList(6), rowList(7), rowList(8))
Loop
请注意,类的默认实例可以被滥用以保持全局状态(例如,就像一些人使用
UserForm
的默认实例的方式)。这并不意味着他们应该这样做。对于属于该类型而不是实例的“静态”方法,使用默认实例,您会做得很好


结合接口,您甚至可以模拟不变性,但我认为您不必为此而去。

使用一个类,命名为cRecord

Option Explicit

Private Type RecordType
    number As String
    group As String
    div As String
    cat As String
    code1 As Integer
    code2 As Integer
    code3 As Integer
    code4 As Integer
    code5 As Integer
End Type

Dim mElement As RecordType

Property Let number(nval As String)
    mElement.number = nval
End Property

Property Let group(nval As String)
    mElement.group = nval
End Property

Property Let div(nval As String)
    mElement.div = nval
End Property

Property Let cat(nval As String)
    mElement.cat = nval
End Property
Property Let code1(nval As String)
    mElement.code1 = nval
End Property

Property Let code2(nval As String)
    mElement.code2 = nval
End Property

Property Let code3(nval As String)
    mElement.code3 = nval
End Property

Property Let code4(nval As String)
    mElement.code4 = nval
End Property

Property Let code5(nval As String)
    mElement.code5 = nval
End Property
然后将代码更改为

Dim placeholder As cRecord
Do Until EOF(1)
    numOfRecords = numOfRecords + 1
    Line Input #1, fileLine
    rowList = Split(fileLine, "|")
    Set placeholder = New cRecord
    placeholder.number = rowList(0)
    placeholder.group = rowList(1)
    placeholder.div = rowList(2)
    placeholder.cat = rowList(3)
    placeholder.code1 = rowList(4)
    placeholder.code2 = rowList(5)
    placeholder.code3 = rowList(6)
    placeholder.code4 = rowList(7)
    placeholder.code5 = rowList(8)

    records.Add placeholder
Loop`

我已经用一个类而不是用户定义的类型测试了您的代码的简化版本,它运行得很好。一个变化是记录。添加占位符。括号被删除。我假设你在我10分钟前发布我的答案时已经开始输入这个答案了——否则它不会带来任何新的东西。FWIW在类名上不需要有
c
前缀(或任何前缀)。另外,只写属性是一种设计味道。是的,我已经开始了,后来看到你更快了:-(当然,另一个主题,类需要通过获取属性和c前缀来“改进”,这只是我做的事情(可能是一个坏习惯),当然不是必需的。谢谢你的回答(+1)-如果可以,请详细说明或指出有关“全局状态”/“静态”默认实例实践的良好来源,和/或实例应该放在哪里更好。@VictorK讨论了默认实例如何经常被滥用(但主要是关于如何避免这样做)-在我不久前写的一篇文章中,我演示了OOP+DI和工厂方法。指导原则是默认实例不应持有任何状态,即不调用其
属性Let
成员,也不分配其任何字段。本质上,这与C中管理
静态类的设计原则完全相同#(
VB.NET中的共享类
)。谢谢你的链接,我很感激!
Dim placeholder As cRecord
Do Until EOF(1)
    numOfRecords = numOfRecords + 1
    Line Input #1, fileLine
    rowList = Split(fileLine, "|")
    Set placeholder = New cRecord
    placeholder.number = rowList(0)
    placeholder.group = rowList(1)
    placeholder.div = rowList(2)
    placeholder.cat = rowList(3)
    placeholder.code1 = rowList(4)
    placeholder.code2 = rowList(5)
    placeholder.code3 = rowList(6)
    placeholder.code4 = rowList(7)
    placeholder.code5 = rowList(8)

    records.Add placeholder
Loop`